2

I am unable to set context state in my app.js, I get empty values in it somehow, but can access it in child component.

I want to set context state in app.js whenever user comes to page so that I can use it throughout the application, for example show different headers based on whether user is logged in or not

SandBox URL as requested -> https://codesandbox.io/s/quizzical-snyder-2qghj?file=/src/App.js

I am following https://upmostly.com/tutorials/how-to-use-the-usecontext-hook-in-react

app.js

// import installed dependencies
import React, { useEffect, useContext } from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';

// import custom contexts
import { AuthContext, AuthContextProvider } from './contexts/auth/AuthContext';

// import pages
import Homepage from './pages/homepage/Homepage';

// import components
import Footer from './components/footer/Footer';
import Header from './components/header/Header';

export default function App() {
    const [authState, setAuthState] = useContext(AuthContext);

    useEffect(() => {
        console.log(authState); // prints *{}*
        console.log(setAuthState); // prints *() => {}*
        const token = localStorage.getItem('token');
        const tokenIsExpired = parseInt(localStorage.getItem('tokenIsExpired'));

        if (!tokenIsExpired && token.length) {
            setAuthState({
                userIsLoggedin: true,
                fName: 'test fname',
                lName: 'test lname',
                userName: 'testname'
            });
        } else {
            setAuthState({
                userIsLoggedin: false,
                fName: '',
                lName: '',
                userName: ''
            });
        }

        if (tokenIsExpired) {
            localStorage.setItem('token', '');
        }
    }, [authState, setAuthState]);

    return (
        <Router>
            <AuthContextProvider value={[authState, setAuthState]}>
                <div className='App'>
                    <Header />
                    <Switch>
                        <Route exact path='/'>
                            <Homepage />
                        </Route>
                    </Switch>
                    <Footer />
                </div>
            </AuthContextProvider>
        </Router>
    );
}

AuthContext.js

import React, { useState, createContext } from 'react';

const AuthContext = createContext([{}, () => {}]);

const AuthContextProvider = (props) => {
    const [authState, setAuthState] = useState({
        userIsLoggedin: false,
        fName: '',
        lName: '',
        userName: ''
    });
    return (
        <AuthContext.Provider value={[authState, setAuthState]}>
            {props.children}
        </AuthContext.Provider>
    );
};

export { AuthContext, AuthContextProvider };

UseAuthCOntext.js

import { useContext } from 'react';
import { AuthContext } from './AuthContext';

const useAuthContext = () => {
    const [authState, setAuthState] = useContext(AuthContext);

    const login = (loginDetails) => {
        setAuthState({
            userIsLoggedin: true,
            fName: 'test fname',
            lName: 'test lname',
            userName: 'testname'
        });
    };

    const logout = () => {
        setAuthState({
            userIsLoggedin: false,
            fName: '',
            lName: '',
            userName: ''
        });
    };

    return { login, logout };
};

export default useAuthContext;

Header.js

// import installed dependencies
import React, { useContext, useEffect } from 'react';

// import components
import LoggedOutHeader from './logged-out-header/LoggedOutHeader';
import LoggedInHeader from './logged-in-header/LoggedInHeader';

// import custom contexts
import { AuthContext } from '../../contexts/auth/AuthContext';

const Header = () => {
    const [authState, setAuthState] = useContext(AuthContext);
    console.log(authState);  //prints *{userIsLoggedin: false, fName: "", lName: "", userName: ""}*
    console.log(setAuthState); //prints *ƒ dispatchAction(fiber, queue, action) {...*
    const header = authState.isUserLoggedIn ? (
        <LoggedInHeader />
    ) : (
        <LoggedOutHeader />
    );

    return header;
};

export default Header;
2
  • Rule 101 never add the setter function in the dependency array of useeffect Commented Jun 30, 2020 at 7:11
  • Please create a sandbox and share Commented Jun 30, 2020 at 7:14

3 Answers 3

8

You could use the context provider inside index.js.

ReactDOM.render(
    <AuthContextProvider>
        <App />
    </AuthContextProvider>, 
    document.getElementById('root')
)
Sign up to request clarification or add additional context in comments.

Comments

1

Your are using the context in the App component, which is not wrapped within AuthContextProvider. In that case the useContext call in the App component will not return the value provided to AuthContextProvider but instead it'll return the "default" values provided to the createContext call.

You need to defer those logic in the App component to a children component within AuthContextProvider.

See note from createContext api: The defaultValue argument is only used when a component does not have a matching Provider above it in the tree. This can be helpful for testing components in isolation without wrapping them. Note: passing undefined as a Provider value does not cause consuming components to use defaultValue.

Comments

0

You are passing value to AuthContextProvider, which seems like the value you want to use, and you don't use it.

// value not used inside `AuthContextProvider`
<AuthContextProvider value={[authState, setAuthState]}>

It should be:

const AuthContextProvider = (props) => {
  return (
    <AuthContext.Provider value={props.value}>
      {props.children}
    </AuthContext.Provider>
  );
};

3 Comments

still getting same empty values in app.js
added sandbox in question

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.