所以我有一些深度嵌套的独立组件,它们需要相互通信。例如,我有一个新闻概述,其中包含一个提要,它可以从导航中折叠/隐藏。导航在DOM中的位置与新闻提要完全不同,因此传递道具是不可能的。
由于我对多个组件有这种依赖关系,我现在已经实现了一个React Context来处理这些状态。为了访问每个组件,上下文会包裹整个应用程序。
这是一个好的练习吗?还是我应该改为EventBus
?
const eventBus = {
on(event, callback) {
// ...
},
dispatch(event, data) {
// ...
},
remove(event, callback) {
// ...
},
};
与
<CustomThemeProvider>
<Component {...pageProps} /> // app
</CustomThemeProvider>
这里的最佳做法是什么?
考虑这个代码片段:
//providers
<AccountContext.Provider value={{...this.state, onAccountLastVisited}}>
...
<VersionContext.Provider value={{...this.state, onUpdateVersion}}>
...
<TrackingContext.Provider value={{...this.state, onCodeTracking}}>
...
<NotificationContext.Provider value={{...this.state, onSendNotification}}>
//consumers
<AccountContext.Consumer>{accContext=> {
...
<VersionContext.Consumer>{verContext=> {
...
<TrackingContext.Consumer>{trkContext=> {
...
<NotificationContext.Consumer>{nftContext=> {
const {onAccountLastVisited} = accContext;
const {onUpdateVersion } = verContext;
const {onCodeTracking } = trkContext;
const {onSendNotification } = nftContext;
...
... onSubmit={()=> {
onAccountLastVisited(eventData);
onUpdateVersion (eventData);
onCodeTracking (eventData);
onSendNotification (eventData);
};}
那看起来很难看。
与无处不在的组件知识紧密结合。
组件被污染了,每当你提出一个新的上下文提供者/使用者时,你就必须回来编辑这个东西。
我不知道你的事,但这伤了我的眼睛。
另一方面:
//listener
EventBus.on('TaskForm.submitClick', onAccountLastVisited);
...
//caller
... onSubmit={()=> {
EventBus.dispatch('TaskForm.submitClick', eventData);
}
就是这样。
现在这个组件对它的父级或提供者一无所知,完全解耦。
非常干净。任何上下文模块都可以侦听事件并执行上下文更新。
无论您的组件事件是向上、向下还是侧向传播,都无关紧要。
我不明白我们为什么不使用事件总线。在这里全面披露,我不是React专家。如果有人能给我一个更好的理由,让我坚持与供应商合作,我会洗耳恭听的。
[EDIT]
再次访问我的答案。事实证明,你可以使用eventBus风格的包。
Akita是为RxJS包构建的,类似于observale-hooks.js。适合运行松散耦合结构。
或者Recoil,它也是与Atom getter&你可以在他们身上做事。
或者React Query。这不是eventBus样式的包。然而,它不仅为您提供了上下文管理,还提供了所有需要照顾的内容,包括高级缓存管理。强烈推荐。
最后一个是好的老Redux RTK RTKQ,我最终发现它被过度设计了,而且我会尽可能选择React Query而不是RTK/Q。
请查看Jack Herrington于2022年1月4日发布的"从20位React State Manager中挑选"。所以,就在你提出这个问题一个月后。他把一切总结得很好。