我正在开发一个 React 应用程序,它有一些嵌套的 React 路由器开关和涉及根据当前显示的页面更改标题内容的非平凡逻辑。
我之前看到过这个问题的两种解决方案:
<Header/>
它完全了解每条可能的路线和应用程序的状态 <Header />
实例在我看来,这两种解决方案都很糟糕。我认为标题必须被喂狗屎并保持在黑暗中。它所要做的就是停留在页面的顶部。受 React Helmet 的启发,我想为这个问题制定一个声明式的解决方案。
假设我们有一个包含三个部分的标题:左、右和中心。在我们应用程序的根部,我们渲染类似
return (
<HeaderLeft>
<Logo />
</HeaderLeft>
...
)
正如预期的那样显示一个标志。在组件树层次结构的更深处,我们有一个
NestedPage
这需要更改标题左侧部分中显示的内容。所以我们简单地做return (
<HeaderLeft>
<SomethingElse />
</HeaderLeft>
...
)
诀窍是当我们离开 NestedPage
时我们需要放回 <HeaderLeft/>
在我们来到 NestedPage
之前就在那里的东西.我想出了一个涉及 react 上下文和堆栈的 +/- 工作解决方案:
https://codesandbox.io/s/great-mendeleev-0b5y4?file=/src/MainPage.js
但是这个东西在很大程度上依赖于 useEffects 的执行顺序。
问题
有没有人有一个模式的惯用解决方案/想法/链接到如何实现所需的结果。
最佳答案
在浏览了 React Helmet 源代码后,我最终使用了 this little jewel
它完全符合我的需要:从渲染顺序中的所有实例同步收集 Prop 。
这样我们就可以得到最后的 children
呈现:
function reducePropsToState(props) {
return props[props.length - 1];
}
棘手的部分是让 Header
组件知道要渲染什么。幸运的是,我们都是软件工程师,React 运行在 javascript 上。我创建了一个简单的 observable 单例:
class Observable {
constructor() {
this.value = null;
this.subscribers = [];
this.raf = null;
this.notify = this.notify.bind(this);
}
subscribe(s) {
this.subscribers.push(s);
s(this.value);
}
setValue(c) {
this.value = c || null;
cancelAnimationFrame(this.raf);
this.raf = requestAnimationFrame(this.notify);
}
notify() {
this.subscribers.forEach((subscriber) => {
subscriber(this.value);
});
}
}
在 header 组件中,我们订阅了这个 observable 并更新本地状态:useLayoutEffect(() => {
contentObservable.subscribe((v) => {
setContent(v);
});
}, []);
Demo in codesandbox
关于reactjs - 带有插槽的 React header 组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65106545/