未免有点标题党, 且先看我写的这个 demo:
import React from 'react';
let obj = null;
let listener = null;
function getObj() { return obj; }
function setListener(l) { listener = l; }
function setObj(o) {
obj = o;
if (listener) { listener(o); }
}
function useObj() {
const [, forceUpdate] = React.useReducer(x=>x+1,0);
React.useEffect(() => {
setListener(() => forceUpdate())
}, [])
return getObj();
}
function Component1() {
return (
<div>
<button onClick={() => {setObj(Math.random())}}>setrandom</button>
</div>
)
}
function Component2() {
const o = useObj();
return (
<div>
{o}
</div>
)
}
export default function App() {
return (
<div>
<Component1 />
<Component2 />
</div>
);
}
先说下 Context 一个缺点, 当数据改变时, 在 Context.Provider 下的节点都会重新执行, 这样很多不用其数据的节点也会被打扰, 昨天的帖子讨论过: 用 Context+Hooks 替代 Redux. 认真看了下大家的评论, 要么是用 memo 来固定住不想被打扰的组件, 要么使用一个订阅模式来刷新并通知.
与其这么麻烦, 不如直接用上面代码中的方法. 毕竟 Context 可以看作是一个全局的数据, 任意节点想使用这个数据时候, 还是需要 import 这个 Context.
上面代码和 redux 很像, 有一个 listener, 但 redux 需要靠 connect 绑定组件来订阅刷新, connect 利用了 Context.Provider+订阅+useSyncExternalStore 这个 API 来实现的.
还不如直接简简单单使用上面这种方式, 当节点使用全局数据时候, 使用自定义 hook 插一个 listener 进去, 当数据变动, 进行 forceUpdate. 这样也会避免了牵一发动全身的全部刷新, 只有使用 useObj() 的组件才会被刷新.
ps. 我写的项目少, 只是看文档时候产生的一点想法. 求大佬指正
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.