Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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"
like image 701
Jac Frall Avatar asked Nov 01 '25 09:11

Jac Frall


1 Answers

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
like image 86
Cherubim Avatar answered Nov 03 '25 23:11

Cherubim



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!