downshift: useSelect `cannot update during an existing state transition` warning using onSelectItemChange with react-router push
downshiftversion: 4.0.1nodeversion: 10.16.3npm(oryarn) version: yarn 1.21.1
Relevant code or config
import React from "react";
import * as ReactDOM from "react-dom";
import {
BrowserRouter as Router,
Switch,
Route,
useHistory
} from "react-router-dom";
import { useSelect } from "downshift";
function App() {
return (
<Router>
<div>
<NavSelect />
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/users">
<Users />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</div>
</Router>
);
}
function NavSelect() {
const { push } = useHistory();
const items = ["/about", "/users", "/"];
const {
getToggleButtonProps,
isOpen,
getMenuProps,
getItemProps
} = useSelect({
onSelectedItemChange: changes => {
push(changes.selectedItem);
},
items
});
return (
<>
<button type="button" {...getToggleButtonProps()}>
Toggle
</button>
<ul {...getMenuProps()}>
{isOpen &&
items.map((item, index) => {
return (
<li key={item} {...getItemProps({ index })}>
{item}
</li>
);
})}
</ul>
</>
);
}
function Home() {
return <h2>Home</h2>;
}
function About() {
return <h2>About</h2>;
}
function Users() {
return <h2>Users</h2>;
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
What you did:
I’m using useSelect with an onSelectItemChange callback that calls react-router’s push function to change the route.
What happened:
The push works, but I end up with this warning in the console:
Warning: Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state.
in NavSelect (at src/index.js:15)
in App (at src/index.js:78)
Reproduction repository:
https://codesandbox.io/s/hopeful-currying-hvx2p
Problem description:
There seems to be some specific incompatibility between where onSelectITemChange is called and how push works. I don’t quite understand it yet. push calls history’s setState (not React’s), which calls notifyListeners which calls react-router’s history listener.
Suggested solution:
Unsure.
onSelectedItemChange: changes => {
setTimeout(() => {
push(changes.selectedItem);
});
},
works as a workaround.
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 2
- Comments: 17 (6 by maintainers)
🎉 This issue has been resolved in version 4.0.8 🎉
The release is available on:
npm package (@latest dist-tag)Your semantic-release bot 📦🚀
@silviuavram I prepared pull request and tested it with
react-router-domandreact-instantsearch-dom, works good as for me.