1
0
Fork 0
Obsidian 管理的个人笔记仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

15 lines
4.8 KiB

{
"nodes":[
{"id":"70300943eedb4f0d","x":-903,"y":-556,"width":742,"height":219,"type":"text","text":"## create\n从 zustand/react.ts 文件开始,先看看 create 函数的代码实现。\n```tsx\nexport const create = (<T>(createState: StateCreator<T, [], []> | undefined) => {\n\t// creare 函数的核心是 createImpl 函数\n\tcreateState ? createImpl(createState) : createImpl) as Create\n}\n```"},
{"id":"8a1c4d4e899e9dad","x":-903,"y":-248,"width":974,"height":400,"type":"text","text":"## createImpl\n从 createImpl 函数的代码中可以看到,调用了 Object.assign() 函数合并 useBoundStore 和 api 对象,这也是为什么,通过 create 创建返回的 Hook 可以在没有 React 的环境通过访问内部属性的方式执行。\n```tsx\nconst createImpl = <T>(createState: StateCreator<T, [], []>) => {\n\t// 判断 createState 是否函数,是则执行 createStore 函数, 否则直接赋值为 createState\n\tconst api = typeof createState === \"function\" ? createStore(createState) : createState;\n\tconst useBoundStore: any = (selector?: any, equalityFn?: any) => useStore(api, selector, equalityFn);\n\t// 合并 api 到 useBoundStore,实际上就是合并到 useStore 执行之后的返回值,因为函数也是对象\n\tObject.assign(useBoundStore, api);\n\t// 最后将 useBoundStore 返回,完成 store 创建\n\treturn useBoundStore;\n};\n```\ncreateImpl 函数中用到了了两个函数,分别是 createStore 和 useStore"},
{"id":"5a13c2f7db73d51f","x":-903,"y":251,"width":838,"height":191,"type":"text","text":"## createStore\n```tsx\nexport const createStore = ((createState) => {\n\t// 判断 createState 是否存在,是则执行 createStoreImpl,否则直接赋值为 createStoreImpl\n\tcreateState ? createStoreImpl(createState) : createStoreImpl) as CreateStore\n}\n```"},
{"id":"1c7f002a32cbff2b","x":135,"y":251,"width":682,"height":505,"type":"text","text":"## useStore\nuseStore 的核心就是 useSyncExternalStoreWithSelector,或者说 zustand 的核心就是这个 Hook\n```tsx\nexport function useStore<TState, StateSlice>(\n\tapi: WithReact<StoreApi<TState>>,\n\tselector: (state: TState) => StateSlice = api.getState as any,\n\tequalityFn?: (a: StateSlice, b: StateSlice) => boolean\n) {\n\t// 自定义一个基于 useSyncExternalStoreWithSelector 的 Hook 并返回\n\tconst slice = useSyncExternalStoreWithSelector(\n\t\tapi.subscribe,\n\t\tapi.getState,\n\t\tapi.getServerState || api.getState,\n\t\tselector,equalityFn\n\t);\n\tuseDebugValue(slice);\n\treturn slice;\n}\n```"},
{"id":"248404eda186b79c","x":-903,"y":545,"width":916,"height":1115,"type":"text","text":"## createStoreImpl\n```tsx\nconst createStoreImpl: CreateStoreImpl = (createState) => {\n\ttype TState = ReturnType<typeof createState>;\n\ttype Listener = (state: TState, prevState: TState) => void;\n\tlet state: TState;\n\tconst listeners: Set<Listener> = new Set();\n\t\n\tconst setState: StoreApi<TState>[\"setState\"] = (partial, replace) => {\n\t\t// 判断传入的参数是否为函数,是则执行函数后将返回值赋值给为 state\n\t\tconst nextState =\n\t\t typeof partial === \"function\"\n\t\t\t ? (partial as (state: TState) => TState)(state)\n\t\t\t : partial;\n\t\t// 比较 nextState 和 state 是否相同,相同则跳过后续逻辑\n\t\tif (!Object.is(nextState, state)) {\n\t\t\tconst previousState = state;\n\t\t\t// 根据 replace 参数决定是否覆盖 state\n\t\t\tstate =\n\t\t\t\treplace ?? typeof nextState !== \"object\"\n\t\t\t\t\t? (nextState as TState)\n\t\t\t\t\t: Object.assign({}, state, nextState);\n\t\t\t// 触发 listener\n\t\t\tlisteners.forEach((listener) => listener(state, previousState));\n\t\t}\n\t};\n\n\t// Get 函数非常简单\n\tconst getState: StoreApi<TState>[\"getState\"] = () => state;\n\n\t// 订阅函数也很简单,listeners 是个 Set,内部存放的将会是 React 防止的回调\n\tconst subscribe: StoreApi<TState>[\"subscribe\"] = (listener) => {\n\t\tlisteners.add(listener);\n\t\t// 返回一个用于取消订阅的函数\n\t\treturn () => listeners.delete(listener);\n\t};\n\n\t// 清空 listeners\n\tconst destroy: StoreApi<TState>[\"destroy\"] = () => {\n\t\tlisteners.clear();\n\t};\n\n\t// 返回\n\tconst api = { setState, getState, subscribe, destroy };\n\tstate = createState(setState, getState, api);\n\treturn api as any;\n};\n```"}
],
"edges":[
{"id":"1b4e70ab90f0b813","fromNode":"70300943eedb4f0d","fromSide":"bottom","toNode":"8a1c4d4e899e9dad","toSide":"top"},
{"id":"9bc83a725e3d3891","fromNode":"8a1c4d4e899e9dad","fromSide":"bottom","toNode":"1c7f002a32cbff2b","toSide":"top"},
{"id":"cc9bb810ea8176d6","fromNode":"8a1c4d4e899e9dad","fromSide":"bottom","toNode":"5a13c2f7db73d51f","toSide":"top"},
{"id":"1ce7dfe29e4f83b3","fromNode":"5a13c2f7db73d51f","fromSide":"bottom","toNode":"248404eda186b79c","toSide":"top"}
]
}