3

Why does the state reset in react component when changing between pages using react-router?


As I understand it, you should be able to switch between routes (components) using react-router as long as you use the 'react' way of changing, ie. <Link to="/otherRoute" />. This is not the case for me and I do not see why. Here is the code:

App.js


import RoutesComp from "./RoutesComp";
import { Link } from "react-router-dom";

function App() {
  return (
    <div className="App">
      <p>
        <Link to="/state">State</Link>
      </p>
      <p>
        <Link to="/dummy">dummy</Link>
      </p>
      <RoutesComp />
    </div>
  );
}

export default App;

StateComp.js

import React, { useState } from "react";

const StateComp = () => {
  const [counter, setCounter] = useState(0);

  return (
    <>
      <button onClick={() => setCounter((prev) => prev + 1)}>click to increment</button>
      <p>{counter}</p>{" "}
    </>
  );
};

export default StateComp

RoutesComp.js

import React from "react";

import { Route, Switch } from "react-router-dom";
import StateComp from "./StateComp";
import Dummy from "./Dummy";

const RoutesComp = (props) => {
  return (
    <>
      <Switch>
        <Route path="/state" render={() => <StateComp />} />
        <Route path="/dummy" render={() => <Dummy />} />

// I also tried it the original way
        {/* <Route path="/state">
          <StateComp />
        </Route>
        <Route path="/dummy">
          <Dummy />
        </Route> */}
      </Switch>
    </>
  );
};

export default RoutesComp;

This produces the following:

enter image description here

When you click on the increment button, the count goes up, but when you go to the 'dummy' page and come back to the 'state' page, the counter is at 0 again.

From my research, react router difference between component and render it looks like the state will be reset if you create routes using

<Route path="/state">
    <StateComp />
</Route>
<Route path="/dummy">
    <Dummy />
</Route>

However, it seems like the way to get the state to not be reset is to use render={() => <Comp/>}. I tried that as well and that did not work.

Can anyone offer some insight as to what I'm doing wrong?


EDIT: Dependencies/Versions

"dependencies": {
    "@testing-library/jest-dom": "^5.14.1",
    "@testing-library/react": "^11.2.7",
    "@testing-library/user-event": "^12.8.3",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-router": "^5.0.0",
    "react-router-dom": "^5.0.0",
    "react-scripts": "4.0.3",
    "web-vitals": "^1.1.2"
Jac Frall
  • 403
  • 7
  • 15
  • Hi, I've did a little digging around this topic. Looks like this answers your question: https://stackoverflow.com/a/45930922/5281962 . In short, don't use `Switch` component and use the `children` prop for the `Route` component. Here's an example that I have implemented: https://codesandbox.io/s/persist-state-react-router-1t4bl – Cherubim Oct 16 '21 at 16:40
  • @Cherubim thanks for this guidance. This helps me out. Though, I am disappointed that there seems to be no built in way to do this with react-router. I guess one way is to lift the state up outside of the component that rerenders using redux or the context API. – Jac Frall Oct 17 '21 at 02:33
  • @Cherubim Please feel free to put your comment as an answer and I will gladly select it as the best answer – Jac Frall Oct 17 '21 at 02:34

1 Answers1

3

The Switch component only ever renders a single route, the earliest match wins. All the components whose routes do not get matched are unmounted.

To avoid this, you need to move you Route components outside of the Switch component and use the children property to render your component.

Here's an example that implements the above mentioned approach: example codesandbox link

Some other workarounds include:

  1. Lifting up your state using either redux or useContext API
  2. use the url parameters to store the state(not suitable for complex components)

Helpful links:

  1. React-router: never unmount a component on a route once mounted, even if route change
  2. How to persist state across react router transitions
Cherubim
  • 5,287
  • 3
  • 20
  • 37