javascript - React: Change component's children from the outside
问题描述
In a React project, I have a component Header.js
, which is part of the global layout and is used on every page. Routing is done with React Router v4.
The Header.js
component should have different children (like breadcrumbs or titles), depending on the page I'm currently on.
Example: on the HomePage.js
, I want to display breadcrumbs. But on the AboutPage.js
, I want to have just a title.
<App>
<Header />
<AnotherComponent />
<MoreComponents />
<BrowserRouter>
...
</BrowserRouter>
</App>
I thought about making Header.js
a HOC, but I can't embed it onto every page because of layout and styling reasons. It needs to be in App.js
in the exact same position.
Any ideas / techniques?
EDIT: Ideally, I want to have the content of Header.js
in every page, like the Helmet package does it:
<>
{/* HomePage.js */}
<HeaderPortal>
<p>Content for the header</p>
</HeaderPortal>
<PageContent />
</>
解决方案
一种方法是使用 React 的上下文 API,但您必须在 DOM 中进行相当高的包装,以便能够从任何地方提供标头内容的 setter 和 getter。
Header 组件如下所示:
const HeaderContext = React.createContext();
// Provides the context and state - wrap app
export class HeaderProvider extends React.Component {
state = {};
render() {
const { children } = this.props;
return (
<HeaderContext.Provider
value={{
header: this.state.header,
setHeader: ({ header }) => this.setState({ header })
}}
>
{children}
</HeaderContext.Provider>
);
}
}
// Wrapper around WHERE the header will be rendered
export function HeaderPlacement() {
return (
<HeaderContext.Consumer>{({ header }) => header}</HeaderContext.Consumer>
);
}
// Wrapper for setting the header CONTENT
export function HeaderPortal({ children }) {
return (
<HeaderContext.Consumer>
{({ header, setHeader }) =>
!header // Guard against setting the header in an endless loop
&& setHeader({ header: children })}
</HeaderContext.Consumer>
);
}
然后用法如下所示:
function App() {
return (
<HeaderProvider>
<div className="App">
<HeaderPlacement />
<Page />
</div>
</HeaderProvider>
);
}
function Page() {
return (
<React.Fragment>
<HeaderPortal><h1>Page A Test</h1></HeaderPortal>
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In ex odio,
eleifend in consequat nec, maximus lobortis ligula. Duis elementum, diam
et imperdiet pulvinar, nulla ligula commodo elit, ac ullamcorper justo
mauris quis velit.
</div>
</React.Fragment>
);
}
如果多个后代尝试设置标题内容,则必须小心,因为您最终会遇到循环setState
问题,或者一个会覆盖另一个。
这绝对不是唯一的方法,我避免使用钩子,但这肯定是React-y 的方法。
在此处查看代码框: https ://codesandbox.io/s/pj2q10700j
推荐阅读
- nginx - 如何使用 Nginx 将 NON HTTP/NON HTTPS 流量重定向到指定 IP?
- python - 在 cx_freeze 设置函数中,name、version 和 description 关键字实际上是做什么的?
- cuda - 如何在 Cuda 内核上启用 RT 内核?
- bash - var 必须包含一个 IP 地址,否则,停止,错误 var 必须是一个 IP 地址,没有别的
- java - 从文件Java中获取矩阵
- keycloak - 如何通过 API 集成 keycloak 短信认证?
- python - 如何在python中导出交叉验证的结果
- c# - 带有 Chromedriver 的 Selenium SendKeys() 使用剪贴板内容而不是电子邮件地址中的“@”字符
- r - 我想在 R 管道工 APi 中添加一个过滤器,它可能会抛出一个无响应 url 的错误
- sql - Netezza:如何为该人找到 LATEST 连续期间的 MIN 和 MAX