https://github.com/MakinoharaShoko/react-usevalue-hook
以下两个组件可以同步状态:
import { useValueWithKey } from 'react-usevalue-hook';
function Comp1() {
const value1 = useValueWithKey(1, 'global1')
return <div onClick={() => { value1.value = value1.value + 1 }}>
{value1.value} Click to +1
</div>
}
function Comp2() {
const value2 = useValueWithKey(2, 'global1')
return <div onClick={() => { value2.value = value2.value + 1 }}>
{value2.value} Click to +1
</div>
}
function App() {
return (
<div style={{padding:20}}>
<div><Comp1 /></div>
<div><Comp2 /></div>
</div>
)
}
export default App
1
SHF 2023-09-01 23:25:40 +08:00
https://github.com/ShenHongFei/react-object-model
我这个状态管理库也很简单,在组件里通过 const { name, age } = user.use(['name', 'age']) 订阅对象的属性,在属性改变时 diff, 重新渲染 |
2
MakinoharaShoko OP @SHF 将一个对象转换为一个全局状态,挺有趣的
|
3
SHF 2023-09-01 23:45:22 +08:00
```ts
export function useValueWithKey<T> (initialState: T, key: string) { const [_, setValue] = useState<T>(initialState) useEffect(() => { // init value(if not set by another component) mkv.init(key, initialState) const handleChange = () => { setValue(mkv.get(key)) } eb.on(`__CHANGED__${key}`, handleChange) handleChange() return () => { eb.off(`__CHANGED__${key}`, handleChange) } }, [ ]) return { set value (newValue: T) { mkv.set(key, newValue) eb.emit(`__CHANGED__${key}`) setValue(newValue) }, get value (): T { return mkv.get(key) ?? initialState } } } ``` useEffect 里面直接调用了 handleChange, 里面执行 setValue 会导致组件挂载之后因为 state 变了又重新 render ,不太好 你试试在组件里面 console.log('render') 看看渲染了几次 |
4
yhvictor 2023-09-01 23:46:40 +08:00
跟 jotai 差不多
|
5
MakinoharaShoko OP @SHF #3 确实不太好,写这个是为了让两个不同初始值的状态能统一,如果不考虑这个问题就不用写这行代码了(我在想什么,给一个 key 的状态设置两个不同的初始值不是用户的问题吗)
|
6
MakinoharaShoko OP @SHF #3 我来加个条件判断,如果获取到的结果等于初始值,就不设置
|
7
SHF 2023-09-02 00:05:00 +08:00
还有个问题,就是 MemoryKV 里面 map 里存了 key 对应的 value. 在 init 的时候添加进 map ,但是在所有使用这个 key 的组件都 unmount 时,应该删除 map 中的 key, 否则就会内存泄漏。map 除了要维护 value ,还要维护使用这个 key 的组件有多少,当使用的组件为 0 时做清理。但这个方法其实在 react 18 里面,如果启用了 strict 模式,组件会被模拟挂载两次,也不好搞,参考 https://stackoverflow.com/questions/72238175/why-useeffect-running-twice-and-how-to-handle-it-well-in-react
|
8
MakinoharaShoko OP @SHF #7 确实有点不好搞,不过如果做成每次执行 useEffect 中的卸载函数时候 -1 ,每次 init 时 +1 ,应该可以解决
|
9
MakinoharaShoko OP @SHF #7 不过这个库更多是用于在做小项目的时候偷懒,内存泄露只取决于 key 的数目,感觉也不会很庞大。我打算再优化优化
|
10
MakinoharaShoko OP @SHF 突然想到一个问题,对于一个全局状态存储库,在组件卸载后把状态留下来,好像是一个正确的行为。其他全局状态存储库的状态初始化是和组件无关的,无论组件是否存在,状态都一直在内存中保留。而我这里只是把初始化放到了组件挂载过程中,其他行为应该要和其他全局状态存储库保持一致。
|
11
SHF 2023-09-02 12:35:20 +08:00
@MakinoharaShoko 喔对
|
12
codehz 2023-09-02 13:06:34 +08:00
useEffect 里搞订阅容易在 react18 的 suspense 和异步模式中出问题
|
13
MakinoharaShoko OP @codehz 是的,但是官方教程(老)确实是这样做的,之后想到新办法再来解决一下
|
14
codehz 2023-09-03 00:58:34 +08:00 via iPhone
@MakinoharaShoko react18 有专门的 useSyncExternalStore
|
15
MakinoharaShoko OP @codehz #14 OK ,我去了解一下
|