简体   繁体   中英

React useContext hook: context becomes null on page reload

I have the following UserContext.js file, which stores the current logged in user into a user object, and also a setter function. In my Profile component, I want to pre-populate my input fields with the current logged in user's information, which I should be getting using useContext hooks.

The app works fine if I navigate to the Profile page normally from the homepage, but when I try to directly access /profile or reload the page while within the Profile page, I am seeing that my context becomes undefined for a split second (as seen by the console.log), before it loads a value. This causes the useEffect() hook and initializeFields() function to fail because the properties are null.

What I want to happen, is to be able to seamlessly load the current logged in user, and also use it globally in other components within the app. Passing the user object from the parent component as props is not feasible because in reality, my app is a few components deep and prop-drilling wouldn't be a very elegant solution.

const UserContext = React.createContext({
  user: {},
  setUser: (user) => {},
});

In the App.js component:

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

  return (
    <div className="app">
      <UserContext.Provider value={{ user, setUser }}>
        <Switch>
          <Route path="/profile" exact component={Profile} />
        </Switch>      
      </UserContext.Provider>
    </div>
  );

The Profile.js component:

const DashboardProfileModal = (props) => {
  const userContext = useContext(UserContext);
  const [name, setName] = useState();
  const [username, setUsername] = useState();
  const [password, setPassword] = useState();
  const [address, setAddress] = useState();

  console.log(userContext)

  useEffect(() => {
    initializeFields();
  });

  const initializeFields = () => {
    setName(userContext.user.name);
    setUsername(userContext.user.username);
    setPassword(userContext.user.password);
    setAddress(userContext.user.address);
  };

I believe the problem you're facing is because you have the provider declared on the App component. If you want it to be globally accessible to the whole application you should have it on your index.js file, wrapping the App component. Something like:

ReactDOM.render(
  <React.StrictMode>
    <UserContext.Provider>
        <App />
    </UserContext.Provider>
  </React.StrictMode>,
  document.getElementById("root")
)

You could do something like below and make sure that userContext is available before attempting to use it.

You should also at least make the useEffect run once on page load by adding the [] (else it will fire constantly on every render). I've also added userContext as a dependency to the useEffect and then I check userContext and name . This means it will ensure userContext is not null before it attempts to run your method.

Then I also include the !name check so that we can ensure it doesn't keep attempting to run your method once your state has been set for the first time.

const DashboardProfileModal = (props) => {
  const userContext = useContext(UserContext);
  const [name, setName] = useState();
  const [username, setUsername] = useState();
  const [password, setPassword] = useState();
  const [address, setAddress] = useState();

  console.log(userContext)

  useEffect(() => {
    if(userContext && !name){
      initializeFields();
    }
  },[userContext]);

  const initializeFields = () => {
    setName(userContext.user.name);
    setUsername(userContext.user.username);
    setPassword(userContext.user.password);
    setAddress(userContext.user.address);
  };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM