Update Context state before component loads

Advertisements

Here I am using react-router and using conditionals for multiple routes. I am using context to store my state. I want to load my data from localStorage to the state before my App.js is loaded as based on that it tells on which routes should I navigate to.

userContext.js

import React, { useState, createContext, useEffect } from "react";

export const userContext = createContext();

export const UserProvider = (props) => {
    const [user, setUser] = useState(null);

    const loadFromLocalStorage = () => {
        try {
            const serializedState = localStorage.getItem("state");
            if (serializedState == null) return undefined;
            return JSON.parse(serializedState);
        } catch (err) {
            console.log(err);
            return null;
        }
    };

    useEffect(() => {
        const state = loadFromLocalStorage();
        console.log("state: ", state);
        setUser(state);
    }, []);

    return (
        <userContext.Provider value={[user, setUser]}>
            {props.children}
        </userContext.Provider>
    );
};

export default userContext;

App.js

import React, { useContext, useEffect } from "react";
import { Switch, Route, Redirect } from "react-router";
import userContext from "./context/userContext";

const App = () => {
    var routes = null;
    const [user, setUser] = useContext(userContext);
    console.log("app: ", user);
    console.log(routes);

    if (user == null) {
        routes = (
            <div>
                <Switch>
                    <Route path="/login" component={SignUp} />
                    <Redirect to="/login"></Redirect>
                </Switch>
            </div>
        );
    } else {
        routes = (
            <div>
                <Switch>
                    <Route exact path="/news" component={NewsList} />
                    <Redirect to="/news"></Redirect> 
                </Switch>
            </div>
        );
    }
    return <div className="App">{routes}</div>;
};

export default App;

>Solution :

Inside your UserProvider, don’t render the children until you’ve loaded data from localstorage. This will require some extra state, but nothing too bad, and this is a common pattern for asynchronous context/state:

export const UserProvider = (props) => {
    const [isReady, setIsReady] = useState(false);

    // other code removed for brevity

    useEffect(() => {
      const state = loadFromLocalStorage();
      setIsReady(true);
    }, [])

    return (
        <userContext.Provider value={[user, setUser]}>
            {isReady ? props.children : null}
        </userContext.Provider>
    );
}

Leave a ReplyCancel reply