state resets when transitioning route(page)

2k views Asked by At

i recreated the problem in this CodeSandbox

https://codesandbox.io/s/competent-newton-up21l?file=/pages/index.js

i have two routes(pages)

  • /
  • /car/info

and two components

  • Header
  • CarInput

i used context to maintain the state and pass it to both the pages.

when im in route /car/info and i change the state using input , the updated state gets displayed in Header component of the same route(page).

But when i go to / route(page) the state is not updated .i inspected using react dev tools and the context doesnt have the updated values .

Even when i go back to /car/info , the updated state is not there too. As soon as i transition to / from /car/info the state goes back to intialState .

Steps to recreate the same on sandbox

  1. click on "go to add car"
  2. enter a car name in the input and click add
  3. click on "go to home"

Now you can see the car you added is not present there .

UPDATE : As pointed out in the answers below , i was updating the localState . i fixed the code to use global state and yet the problem persists .

New SandBox : https://codesandbox.io/s/inspiring-pond-mp134?file=/context/cars-context.js

2

There are 2 answers

0
Mohamed Sauood On BEST ANSWER

when doing a page transition in next.js, the context gets unmounted .

So , Wrapping the context provider in __app.js page makes sure it doesn't get unmounted when doing transition .

2
Sarun UK On

First of all where are you updating the state while adding the car.

  function handleSubmit(e) {
    e.preventDefault();
    let car = e.target.elements["car"].value;
    setCars((prevState) => {
      return [...prevState, car];
    });
  }

The above code I copied from your repo, only updating the newly added car to the local state. That is the reason it is not available in the context. You have created a global context but not using it.

what you have to do is,

Access context in your carInput class

const [initialState, dispatch] = useCarContext();

 
function handleSubmit(e) {
        e.preventDefault();
        let car = e.target.elements["car"].value;
       // Instead of updating to local state, 
      //upadate your global context using dispatch
       // in dispatch pass actionType and the value
       dispatch({ type: 'updateNewCar', value: car });
      }

Also attaching the sample context implementation (you can make changes according to your use case)

import React, { createContext, useContext, useReducer } from "react";

export const initCarContext = () => {
  return {
    initialState: {
      cars: []
    },
    reducer: function (state, { type, value }) {
      switch (type) {
        case 'updateNewCar':
          state.cars.push(value)
          return { ...state };

        default:
          return state;
      }
    }
  };
};

export const StateContext = createContext();
export const CarStateProvider = ({ reducer, initialState, children }) => (
  <StateContext.Provider value={useReducer(reducer, initialState)}>
    {children}
  </StateContext.Provider>
);
export const useCarContext = () => useContext(StateContext);

https://kentcdodds.com/blog/how-to-use-react-context-effectively/