javascriptreactjssession-storage

How to save and retrieve state variables to session storage with React?


I am using React 18.2.0, where I have a BodyComponent that stores results from an API call into states and filters that are used in the call.

The BodyComponent retrieves the results and the filters from the Session Storage at load with a hook, and updates the sessionStorage when the results are updated.

export default function BodyComponent(){

    const [results, setResults] = useState([]);
    const [filters, setFilters] = useState([]);
    
    useEffect(() => {
        if (window.sessionStorage.getItem('results') !== null) {
            setResults(JSON.parse(window.sessionStorage.getItem('results')));
        }
        if (window.sessionStorage.getItem('filters') !== null && filters.length === 0) {
            setFilters(JSON.parse(window.sessionStorage.getItem('filters')));
        }
    }, []);


    useEffect(() => {
        window.sessionStorage.setItem('results', JSON.stringify(results));
    }, [results]);

    return (
    ...
    <FilterComponent filters={filters} setFilters={setFilters}/>
    ...
    )

}

The filter component updates the filters to the session storage :

export default function FilterComponent(props) {
    const {filters, setFilters} = props; 

    useEffect(() => {
        window.sessionStorage.setItem('filters', JSON.stringify(filters));
    }, [filters]);

    return (
    ...
    )
}

When I navigate to another React route and back to the route that loads BodyComponent, filters are saved to the session storage, and BodyComponent successfully retrieves them and passes them to FilterComponent at load.

However, the same is not true for results, which are saved to the session storage but not set to their State on load.

I have tried the following :

What am I missing?


Solution

  • const [results, setResults] = useState([]);
    
    useEffect(() => {
      console.log(results); // results is empty on the first render 
      window.sessionStorage.setItem('results', JSON.stringify(results));
    }, [results]);
    

    When the effect is executed for the first time, results is empty so you reset your results after the initial render.

    From the documentation, useState can take an initializer function to compute the initial state (this function will be called only once when the component is initialized).

    function load(key) {
      const item = window.sessionStorage.getItem(key);
      return item != null ? JSON.parse(item) : [];
    }
    
    export default function BodyComponent(){
        const [results, setResults] = useState(() => load('results'));
        const [filters, setFilters] = useState(() => load('filters'));
    
        useEffect(() => {
            window.sessionStorage.setItem('results', JSON.stringify(results));
        }, [results]);
        
        ....
    }