React-admin更新Context值触发Router History警告问题求助
问题
在React-admin项目中用Context存储全局信息,点击Link组件导航时更新Context数据,控制台弹出「Warning: You cannot change
全局Context配置代码
const AppContext = createContext({ appData: {}, setAppData: () => {}, }); const App = () => { const [appData, setAppData] = useState({ foo: null, }); return ( <AppContext.Provider value={[appData, setAppData]}> <Admin title="My Admin App"> <Resource name="foo" show={ShowFoo} /> </Admin> </AppContext.Provider> ) };
自定义菜单导航组件代码
export const MyMenuLink = ({ primaryText, to, leftIcon, sidebarIsOpen, onMenuClick, dense, foo }) => { const clickHandler = (e) => { const newAppData = { ...appData, foo: foo, }; setAppData(newAppData); }; return ( <Link to={to} onClick={clickHandler}> <Typography variant="inherit">{primaryText}</Typography> </Link> ); };
原因与解决方案
触发警告的核心原因
问题出在组件渲染层级与React-admin内部Router的冲突:
- 你把
AppContext.Provider放在了Admin组件外层,调用setAppData更新Context时,会触发App组件重新渲染。 Admin组件内部封装了React Router的完整实例,重新渲染Admin会导致Router的history对象被强制重建——而React Router要求自身实例在应用生命周期中必须保持稳定,不能随意重建,因此控制台抛出警告。
简言之:更新Context触发外层组件重渲染,导致React-admin内部的Router实例被重新初始化,进而触发history变更警告。
解决方案
把AppContext.Provider移到Admin组件内部,避免更新Context时触发整个Admin的重渲染:
调整后的App组件代码
const AppContext = createContext({ appData: {}, setAppData: () => {}, }); const App = () => { const [appData, setAppData] = useState({ foo: null, }); return ( <Admin title="My Admin App"> <AppContext.Provider value={[appData, setAppData]}> <Resource name="foo" show={ShowFoo} /> </AppContext.Provider> </Admin> ) };
如果需要在整个Admin范围内共享Context,可以通过自定义layout注入Provider,确保Provider在Router实例之后渲染:
const CustomLayout = (props) => { const [appData, setAppData] = useState({ foo: null }); return ( <AppContext.Provider value={[appData, setAppData]}> <Layout {...props} /> </AppContext.Provider> ); }; const App = () => { return ( <Admin title="My Admin App" layout={CustomLayout}> <Resource name="foo" show={ShowFoo} /> </Admin> ) };
修改后,更新Context只会触发Provider内部的组件重渲染,不会影响外层的Admin和Router实例,警告即可消除。
内容的提问来源于stack exchange,提问作者kailoon
相关产品推荐
相关产品推荐

