Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Lift State Up w/ React Router 6?

I am wondering how to share state between my two routes. Should I lift state up from my AddContact component to Layout or App to share to ContactList. My Layout component is just rendering a Header and Outlet component.

function App() {
  const [contacts, setContacts] = useState([])

  return (
    <BrowserRouter>
      <Routes>
        <Route element={<Layout />}>
          <Route path='/' element={<ContactList />} />
          <Route path='/add' element={<AddContact />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}
like image 982
Karnveer Grewal Avatar asked Sep 20 '25 08:09

Karnveer Grewal


2 Answers

You could lift it to either.

If lifting state to App you can pass what you need down as props to each routed component.

Example:

function App() {
  const [contacts, setContacts] = useState([]);

  return (
    <BrowserRouter>
      <Routes>
        <Route element={<Layout />}>
          <Route
            path="/"
            element={<ContactList contacts={contacts} />}
          />
          <Route
            path="/add"
            element={<AddContact setContacts={setContacts} />}
          />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}

The alternative is to locate the state in the Layout layout route component and expose via the Outlet component's context. The routed components would access the provided context value via the useOutletContext hook.

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route element={<Layout />}>
          <Route path="/" element={<ContactList />} />
          <Route path="/add" element={<AddContact />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}
const Layout = () => {
  const [contacts, setContacts] = useState([]);

  return (
    ...
    <Outlet context={{ contacts, setContacts }} />
    ...
  );
};
const ContactList = () => {
  const { contacts } = useOutletContext();

  ...
};
const AddContact = () => {
  const { setContacts } = useOutletContext();

  ...
};

It basically comes down to preference, or scope in my opinion, e.g. how much of the sub-ReactTree needs to access the state.

like image 194
Drew Reese Avatar answered Sep 22 '25 01:09

Drew Reese


Here is an example using states and not state management systems.

Let's assume that we've got 2 sibling components; page1 and page2. If we need to pass data from the page1 component to the page2 component, we can use hooks in react-router-dom v6.

import {Link} from 'react-router-dom';

const Page1 = () => {
  return (
    <Link to={'/page2'} state: {msg: "hello from page1"}>Go to Page2</Link>
  );
}

export default Page1;

On the page2 component, you can receive the object like that.

import { useLocation } from "react-router-dom";

const Page2 = (props) => {
   const { state } = useLocation();
   
   return <div>{state.msg}</div>
 
}

export default Page2;
like image 21
Evan Avatar answered Sep 22 '25 01:09

Evan