英文:
Updating context value in react-admin causes a router history warning
问题
我正在使用上下文(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>
);
};
因此,当我点击该链接时,会出现路由历史警告,但如果我在clickHandler中删除setAppData()调用,警告就会消失。
英文:
I'm using context to store a global piece of information which is updated when navigating around the web app from a Link component. For some reason, when I update the context data, I get a "Warning: You cannot change <Router history>" in the console. My data has no history object in it, just a value and a function to update. What could cause this?
Here is my setup:
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>
)
};
My menu has nav links using this component:
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>
);
};
So when I click on that link, I get the router history warning, but if I remove the setAppData() call in clickHandler, it disappears.
Thanks
答案1
得分: 1
警告:您不能更改 <Router history>
这是来自React Router的消息。React Router支持不同的history对象,但通常您会连接到BrowserHistory
并允许浏览器处理和传播路由更改给路由器。
按下浏览器的前进/后退按钮将触发重新渲染,而不是完全的页面刷新。
React-admin
React-Admin也使用了React-Router。
您可以将一个history传递给根<Admin />
组件。
如果您不设置history,react-admin会为您创建一个。
传递一个history很简单:
import { createBrowserHistory } from "history";
const history = createBrowserHistory();
const App = () => {
return (<Admin
dashboard={Dashboard}
authProvider={authProvider}
dataProvider={dataProvider}
history={history}
/>);
}
重新渲染
React-Router不希望history引用发生变化。
如果您尝试更改它,您将看到警告弹出。
当父组件中的某些内容发生更改时,React将重新渲染子组件。
在您的情况下,当在提供程序中接收到新值时,上下文将重新渲染其子组件。(基本上是在调用setAppData
时)
这将触发<Admin>
组件的重新渲染。
由于我们没有传递history,会创建一个新的history并传递给路由器。可能在这里
然后您将看到React Router的警告。
传入您自己的路由器将解决这个问题。
沙箱
您可以在此沙箱中尝试它。
如果注释掉history属性,您将再次收到警告。
仪表板上有一个链接可以触发重新渲染。
英文:
Warning: You cannot change <Router history>
This is a message coming from React Router. React router supports different history-objects, but usually you would connect to a BrowserHistory
and allow the browsers to handle and propagate route changes to the router.
IE pressing the browsers forward/backward buttons will trigger a re-render, not a total page refresh.
React-admin
React-router is also used by React-Admin.
You can pass along a history into the root <Admin />
component.
If you don't set a history, react-admin will create one for you.
Passing in a history is as simple as:
import {createBrowserHistory} from "history";
const history = createBrowserHistory();
const App = ()=>{
return (<Admin
dashboard={Dashboard}
authProvider={authProvider}
dataProvider={dataProvider}
history={history}
/>)
}
Rerenders
React-router doesn't want the history reference to change.
If you attempt to change it, you'll see the warning pop up.
React will re-render child components when something in the parent changes.
In your case, the context will re-render their children whenever a new value is received in the provider. (basically when calling setAppData
)
This will trigger a rerender on your <Admin>
component.
Since we didn't pass in a history, a new one is created and passed to the router. probably here
You will then see the warning from react router.
Passing in your own router would solve that.
sandbox
You can try it in this sandbox.
If you comment out the the history prop, you will receive warnings again.
There's a link on the dashboard to trigger the re-render.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论