ts声明函数类型

1
2
3
4
5
6
7
8
interface CbCallback {
(cb: () => void): void
}

const c: CbCallback = () => {}

// 这里不传参数或者类型不正确就会报错
c(() => {})

vant-checkboxGroup 组件对于使用对象作为值时的回显

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
在移动开发中

需要对后续复杂操作处理

这时候设置设置单纯的基本类型值就不够用了

我们需要将checkboxGroup选择的值设置为对象

也就是name为一个对象

但是后续如果需要回显

就会发现无法回显了

这是因为回显的对象引用和渲染列表的对象引用不一致,是两个不同的对象

因此是无法回显的

我们需要将要回显的对象引用和整个渲染列其中的对象引用保持一致

也就是设置的result变量数组中的选中项

要和list中对一个的哪一项对象引用一致,就可以正常回显

1
2
3
4
5
<van-checkbox-group v-model="result" ref="checkboxGroup">
<van-checkbox name="a">复选框 a</van-checkbox>
<van-checkbox name="b">复选框 b</van-checkbox>
<van-checkbox name="c">复选框 c</van-checkbox>
</van-checkbox-group>
1
2
3
<van-checkbox-group v-model="result" ref="checkboxGroup">
<van-checkbox v-for="item in list" :name="item">{{item.title}}</van-checkbox>
</van-checkbox-group>
1
2
// 在watch中监听到变化
this.result = [...this.list, ...this.checkedList]

react 通过传递不同的key来清空子组件状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
如何在父组件渲染变化时,清空子组件的状态

父组件状态更新时候 子组件也会更新

虽然会更新,但是子组件不会丢失其已经存在的状态

那么每次在父组件更新时,

传递给子组件每次不同的key属性

子组件就会清空其内部状态(因为是一个全新的组件了)

这样

我们就能避免复杂的清空函数
1
2
3
...
<Child key={key} userId={userId} />
...

关于何时该使用useEffect

1
2
3
4
5
6
7
8
9
10
11
12
尽可能在渲染期间进行计算

不要链式的在effect中set 然后下一个effect依赖上一个effect中set后的值 这样非常低效

effect在页面显示 (初次加载时)要执行一些逻辑 这个时候应该使用它

用户操作的动作导致state发生改变, 这时不应该使用effect监听这个状态 继而 去更新其他状态 这并不合理


# 你可能并不需要effect

https://zh-hans.react.dev/learn/you-might-not-need-an-effect

react useSyncExternalStore hook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
useSyncExternalStore 接收三个函数参数

第一个是订阅,

第一个订阅函数接收一个回调,执行这个回调可以触发react更新渲染,

这个订阅函数通常代表订阅了这个hook的组件更新函数,

你可以把这个订阅函数看做触发器dispath

一般我们在订阅函数用不急于执行触发器,

可以把它存储起来,

等到其他动作执行需要更新渲染组件的时候,

在把存储的所有dispath列表全部执行。

如果有多个组件的useSyncExternalStore 的订阅函数和快照函数都出自同一个实例,

那么他们将会共享状态,

实现另类的react状态数据共享

第二个是快照,

第三个是服务端渲染的快照,第二个和第三个返回的快照的内容必须相同

使用useSyncExternalStore的状态共享

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
let cbs = [];
const useStorage = (key, initValue) => {
//订阅者
const subscribe = (cb) => {
cbs = [...cbs, cb];
return () => {
cbs = cbs.filter(l => l !== cb);
};
}

const emitChange = () => {
for (let cb of cbs) {
cb();
}
}

//返回当前快照
const getSnapshot = () => {
return localStorage.getItem(key) ? JSON.parse(localStorage.getItem(key)) : initValue
}

const updateStorage = (value) => {
localStorage.setItem(key, JSON.stringify(value))
//手动触发Storage的事件
// window.dispatchEvent(new StorageEvent('storage'))
emitChange()
}
const res = useSyncExternalStore(subscribe, getSnapshot)
return [res, updateStorage]
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const [count1, setCount1] = useStorage('count1', 1)

return (
<div className="container mx-auto px-4 py-8 max-w-3xl">
<header className="mb-8 text-center">

<div>
count
<span>
{count1}
</span>
<button onClick={() => setCount1(count1 + 1)}>新增</button>
<button onClick={() => setCount1(count1 - 1)}>减少</button>
</div>

vue模版中的“解构赋值”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 通过下面这种绑定一个动态对象的方式

// 将所有属性给到组件

// 等同于 react 当中的
// react
<Child {...props}/>

// vue
// 如果接受的组件内部已经定义了这些同名属性,传入的属性将无法覆盖,
// 考虑使用计算属性合并新旧属性值
<Popup
...
..
.
:pageConfig="{round: false, closeable: true}"
/>

添加一个微任务

1
2
3
4
5
6
7
8
addMicrotask(callback) {
if (typeof queueMicrotask === "function") {
queueMicrotask(callback)
}
else {
Promise.resolve().then(callback)
}
},

关于react组件拆分时的状态控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
如果父组件有多个子组件,

子组件需要根据父组件的状态来更新自身,

这种情况下,

应该把父组件传递给子组件的属性统一放到一个对象中维护,

这样不管什么状态发生变化,

都只更新这个对象,

不会带来多次的重复渲染,

带来性能问题。