Search code examples
reactjsreact-context

Change values in React Context from a nested class component


I have this userContext file:

import React from 'react'

const userContext = React.createContext({ loggedInUser: {} })

export { userContext }

I provide correctly a value in App:

import { userContext } from './../contexts/UserContext'

class App extends Component {
           //...
    
  componentDidMount = () => {
    this.authServices
      .isLoggedIn()
      .then(response => this.setState({ loggedInUser: response.data })
      .catch(() => this.setUser(undefined))
  }

    
        return (
          <>
            <userContext.Provider value={this.state.loggedInUser}>
              <Navigation/>
            </userContext.Provider>
          </>
        )
    }

And can access that value in any nested component such as in Navigation:

/* ... */
<userContext.Consumer>
    {value => value && <h1>Hi! {value.username}</h1>}
</userContext.Consumer>
/* ... */

How can I change from these nested components such as Navigation the value from the loggedInUser property in the context?

I don't find the way to attach methods to the context and use them, for example, when user logs out in the Navigation component:

/* ... */

logOut = () => {
    this.authService
        .logout()
        .then(() => /* modify here the loggedInUser from the context */ )

/* ... */

Please note this is a stateful component and I need a non-Hooks solution.


Solution

  • First you need to create a function that changes the user data and pass it in a context so child components can leverage it.

    updateUserData = (userInfo) => {
      this.setState({ loggedInUser: userInfo })
    }
    

    After that you can pass that function in the context:

    <userContext.Provider value={{
      loggedInUser: this.state.loggedInUser,
      updateUserData: this.updateUserData
    }}>
      <Navigation/>
    </userContext.Provider>
    

    Since you are accessing context Provider the old way you will need to attach the static contextType = userContext; on top of your class to be able to access context value like this outside of your render method:

    const { loggedInUser, updateUserData } = this.context;
    

    Now in your logOut access the updateUserData like above and pass it the new userData.

    Here is more info about contextType: https://reactjs.org/docs/context.html#classcontexttype