V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
MakinoharaShoko
V2EX  ›  React

一个真的仅需一行代码就可以配置的 React 全局状态库,但是功能也仅限于此

  •  1
     
  •   MakinoharaShoko ·
    MakinoharaShoko · 2023-09-01 23:19:49 +08:00 · 1787 次点击
    这是一个创建于 444 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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
    
    15 条回复    2023-09-03 19:53:00 +08:00
    SHF
        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, 重新渲染
    MakinoharaShoko
        2
    MakinoharaShoko  
    OP
       2023-09-01 23:40:41 +08:00
    @SHF 将一个对象转换为一个全局状态,挺有趣的
    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') 看看渲染了几次
    yhvictor
        4
    yhvictor  
       2023-09-01 23:46:40 +08:00
    跟 jotai 差不多
    MakinoharaShoko
        5
    MakinoharaShoko  
    OP
       2023-09-01 23:49:33 +08:00
    @SHF #3 确实不太好,写这个是为了让两个不同初始值的状态能统一,如果不考虑这个问题就不用写这行代码了(我在想什么,给一个 key 的状态设置两个不同的初始值不是用户的问题吗)
    MakinoharaShoko
        6
    MakinoharaShoko  
    OP
       2023-09-01 23:51:31 +08:00
    @SHF #3 我来加个条件判断,如果获取到的结果等于初始值,就不设置
    SHF
        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
    MakinoharaShoko
        8
    MakinoharaShoko  
    OP
       2023-09-02 00:07:58 +08:00
    @SHF #7 确实有点不好搞,不过如果做成每次执行 useEffect 中的卸载函数时候 -1 ,每次 init 时 +1 ,应该可以解决
    MakinoharaShoko
        9
    MakinoharaShoko  
    OP
       2023-09-02 00:10:47 +08:00
    @SHF #7 不过这个库更多是用于在做小项目的时候偷懒,内存泄露只取决于 key 的数目,感觉也不会很庞大。我打算再优化优化
    MakinoharaShoko
        10
    MakinoharaShoko  
    OP
       2023-09-02 01:35:03 +08:00 via Android
    @SHF 突然想到一个问题,对于一个全局状态存储库,在组件卸载后把状态留下来,好像是一个正确的行为。其他全局状态存储库的状态初始化是和组件无关的,无论组件是否存在,状态都一直在内存中保留。而我这里只是把初始化放到了组件挂载过程中,其他行为应该要和其他全局状态存储库保持一致。
    SHF
        11
    SHF  
       2023-09-02 12:35:20 +08:00
    codehz
        12
    codehz  
       2023-09-02 13:06:34 +08:00
    useEffect 里搞订阅容易在 react18 的 suspense 和异步模式中出问题
    MakinoharaShoko
        13
    MakinoharaShoko  
    OP
       2023-09-02 22:33:12 +08:00
    @codehz 是的,但是官方教程(老)确实是这样做的,之后想到新办法再来解决一下
    codehz
        14
    codehz  
       2023-09-03 00:58:34 +08:00 via iPhone
    @MakinoharaShoko react18 有专门的 useSyncExternalStore
    MakinoharaShoko
        15
    MakinoharaShoko  
    OP
       2023-09-03 19:53:00 +08:00
    @codehz #14 OK ,我去了解一下
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3377 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 12:22 · PVG 20:22 · LAX 04:22 · JFK 07:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.