【发布时间】:2021-08-05 04:11:18
【问题描述】:
我正在将项目从类组件切换到功能组件,并在使用上下文时遇到问题。
我有一个父布局,其中包含一个打开和关闭的导航菜单(通过父级中的状态更改)。这个布局组件还包含一个我通过上下文传递的用户属性。
在切换到功能组件和钩子之前,一切都很好。
我现在看到的问题是,当从布局组件(父级)打开导航菜单时,会导致子组件重新渲染。如果上下文发生变化,我会期待这种行为,但它没有。这也仅在将 useContext 添加到子项时才会发生。
我正在导出带有备忘录的孩子,还尝试用带有备忘录的孩子包装一个容器,但它没有帮助(实际上它似乎导致更多的渲染)。
下面是代码大纲:
AppContext.tsx
export interface IAppContext {
user?: IUser;
}
export const AppContext = React.createContext<IAppContext>({});
routes.tsx
...
export const routes = <Layout>
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/metrics' component={Metrics} />
<Redirect to="/" />
</Switch>
</Layout>;
布局.tsx
...
const NavItems: any[] = [
{ route: "/metrics", name: "Metrics" }
];
export function Layout({ children }) {
const aborter = new AbortController();
const history = useHistory();
const [user, setUser] = React.useState<IUser>(null);
const [navOpen, setNavOpen] = React.useState<boolean>(false);
const [locationPath, setLocationPath] = React.useState<string>(location.pathname);
const contextValue = {
user
};
const closeNav = () => {
if (navOpen)
setNavOpen(false);
};
const cycleNav = () => {
setNavOpen(prev => !prev);
};
React.useEffect(() => {
Fetch.get("/api/GetUser", "json", aborter.signal)
.then((user) => !aborter.signal.aborted && !!user && setUser(user))
.catch(err => err.name !== 'AbortError' && console.error('Error: ', err));
return () => {
aborter.abort();
}
}, []);
React.useEffect(() => {
return history.listen((location) => {
if (location.pathname != locationPath)
setLocationPath(location.pathname);
})
}, [history]);
const navLinks = NavItems.map((nav, i) => <li key={i}><Link to={nav.route} onClick={closeNav}>{nav.name}</Link></li>);
return (
<div className="main-wrapper layout-grid">
<header>
<div className="header-bar">
<div className="header-content">
<div className="mobile-links-wrapper">
<ul>
<li>
<div className="mobile-nav-bars" onClick={cycleNav}>
<Icon iconName="GlobalNavButton" />
</div>
</li>
</ul>
</div>
</div>
</div>
<Collapse className="mobile-nav" isOpen={navOpen}>
<ul>
{navLinks}
</ul>
</Collapse>
</header>
<AppContext.Provider value={contextValue} >
<main role="main">
{children}
</main>
</AppContext.Provider>
<a target="_blank" id="hidden-download" style={{ display: "none" }}></a>
</div>
);
}
Metrics.tsx
...
function Metrics() {
//Adding this causes re-renders, regardless if I use it
const { user } = React.useContext(AppContext);
...
}
export default React.memo(Metrics);
我有什么遗漏吗?当布局组件中的navOpen状态发生变化时,如何让metrics组件停止渲染?
我已经在路由器中和街区周围尝试了备忘录。我也尝试过移动 contextprovider,但没有成功。
【问题讨论】:
标签: reactjs react-hooks