Jotai 源码解读

 

Jotai 是 React 生态中的一个状态管理库,它提供了便捷的 API,使用起来很灵活,下面是通过阅读源码发现的一些实现原理。

Jotai 中的数据(store)通过 memory 保存,和框架没有关系,内部的 store 实例使用了 WeakMap 做 atom 的映射,并且允许存在多个 store 实例,如果需要对不同的 store 对象进行隔离,可以在 React 中使用 jotai 提供的 Provider 组件,但是一般在项目开发中,只会用到一个 store 实例。

useAtomValue 通过 useReducer 来触发 re-render:

import { useStore } from 'jotai'

// 源码简化版
export function useAtomValue(atom) {
  // 获取 store 实例
  const store = useStore()

  const [[valueFromReducer, storeFromReducer, atomFromReducer], rerender] =
    useReducer(
      (prev) => {
        const nextValue = store.get(atom)
        if (
          Object.is(prev[0], nextValue) &&
          prev[1] === store &&
          prev[2] === atom
        ) {
          return prev
        }
        return [nextValue, store, atom]
      },
      undefined,
      () => [store.get(atom), store, atom]
    )

  let value = valueFromReducer

  useEffect(() => {
    const unsub = store.sub(atom, () => {  // * 监听变化
      rerender()
    })
    
    rerender()
    return unsub
  }, [store, atom])

  return value
}
import { atom, useAtomValue } from 'jotai'

export const valueAtom = atom("hello")

export function Greeting() {   
    const value = useAtomValue(valueAtom)
    
    return <p>{value}</p>
}

如果 value 的值发生变更,Jotai 会比较这个 atom 的值,如果上次的值和这次的值不相同,则会修改 store 中的值,然后发通知给订阅了这个 atom 的函数(用上面的代码中用 * 注释标记了),函数 A 中调用当前 react 上下文中 reducer 的 dispatch 方法来更新视图,通过这种方式修改 state,可以应用于多个 React 实例中,只要一个地方更改了 value,所有获取了 value 值的 React 上下文都会触发重新渲染,因为当前的 value 并不是存在某一个 React 实例当中。