React:无法使用useContext钩子在app.js中设置上下文状态

时间:2020-06-30 06:59:36

标签: javascript reactjs react-hooks react-context

我无法在app.js中设置上下文状态,我以某种方式获得了空值,但可以在子组件中访问它。

我想在用户访问页面时在app.js中设置上下文状态,以便我可以在整个应用程序中使用它,例如,根据用户是否登录显示不同的标题

沙盒网址(按要求) -> https://codesandbox.io/s/quizzical-snyder-2qghj?file=/src/App.js

我正在关注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;

3 个答案:

答案 0 :(得分:1)

您可以在 index.js 中使用上下文提供程序。

ReactDOM.render(
    <AuthContextProvider>
        <App />
    </AuthContextProvider>, 
    document.getElementById('root')
)

答案 1 :(得分:0)

您正在将cond_t cond; 2 mutex_t mutex; 3 4 void *producer(void *arg) { 5 int i; 6 for (i = 0; i < loops; i++) { 7 Pthread_mutex_lock(&mutex); // p1 8 if(count == 1) // p2 9 Pthread_cond_wait(&cond, &mutex); // p3 10 put(i); // p4 11 Pthread_cond_signal(&cond); // p5 12 Pthread_mutex_unlock(&mutex); // p6 13 } 14 } 15 16 void *consumer(void *arg) { 17 int i; 18 for (i = 0; i < loops; i++) { 19 Pthread_mutex_lock(&mutex); // c1 20 if(count == 0) // c2 21 Pthread_cond_wait(&cond, &mutex); // c3 22 int tmp = get(); // c4 23 Pthread_cond_signal(&cond); // c5 24 Pthread_mutex_unlock(&mutex); // c6 25 printf("%d\n", tmp); 26 } 27 } 传递给value,这似乎是您要使用的AuthContextProvider,但您并未使用它。

value

应该是:

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

答案 2 :(得分:0)

您正在使用App组件中的上下文,该上下文未包装在AuthContextProvider中。在那种情况下,App组件中的useContext调用将不会返回提供给AuthContextProvider的值,而是会返回提供给createContext调用的“默认”值。

您需要将App组件中的逻辑推迟到AuthContextProvider中的子组件。

请参阅createContext api中的注释: defaultValue参数为,仅当组件在树中上方没有匹配的提供程序时使用。。这对于隔离测试组件而不包装它们很有帮助。注意:将undefined传递为Provider值不会导致使用组件使用defaultValue。