用户授权后如何在所有子组件之间传递状态?

How to pass state between all child components after user authorization?

服务器正在返回用户数据。我尤其对他的权利感兴趣。有了这些权利,我将渲染组件。我正在考虑将这些数据传递给组件并进行一些检查。所有路线都在index.js

import {Notfound404} from './components/404/404NotFound'
import {UserContext} from './UserContext'

const Router = () => {

    const [user, setUser] = useState(null)

    return (
        <React.StrictMode>
            <UserContext.Provider value={{user, setUser}}>
                <CookiesProvider>
                    <BrowserRouter>
                        <Switch>
                            <Route exact path={'/'} component={Auth}/>
                            <Route exact path={'/settings'} component={Settings}/>
                            <Route exact path={'/event-logs'} component={EventLog}/>
                            <Route component={Notfound404} status={404}/>
                        </Switch>
                    </BrowserRouter>
                </CookiesProvider>
            </UserContext.Provider>
        </React.StrictMode>
    )
}

在 Auth.js

中设置用户数据
import {UserContext} from '../../UserContext'

export const Auth = () => {

    const {user, setUser} = useContext(UserContext)

    const [username, setUsername] = useState('')
    const [password, setPassword] = useState('')
    const [token, setToken] = useCookies(['qr-token'])

    useEffect(() => {
        if (token['qr-token']) window.location.href = '/settings'
    }, [token])

    const credentials = {
        username: username,
        password: password
    }

    const sendCredentials = () => {
        axios.post(`http://127.0.0.1:8000/api/v1/auth/`, credentials, {
            headers: {
                'Content-type': 'application/json',
            }
        })
            .then(resp => {
                setToken('qr-token', resp.data.token);
                setUser(resp.data)
            })
            .catch(error => console.log(error.response))
    }

    return !token['qr-token'] &&
        <div className={styles.authContainer}>
            <label htmlFor={'username'}>Username</label>
            <input id={'username'} type={'text'} placeholder={'username'}
                   onChange={evt => setUsername(evt.target.value)}
            />
            <label htmlFor={'password'}>Password</label>
            <input id={'password'} type={'password'} onChange={evt => 
                setPassword(evt.target.value)}/>
            <button onClick={sendCredentials}>Sign In</button>
        </div>
    )
}

在 index.js 中,我在授权后获取用户数据。但是在settings.js use data is null

export const Settings = () => {

    const {user, setUser} = useContext(UserContext)
    console.log(user) # null
....
}

可能我做错了什么,我请求你的帮助。谢谢

我认为重定向到设置页面时正在刷新。重新加载导致上下文值被清除(简单地说,因为上下文的值来自一个状态,而该状态由于刷新而丢失)。要解决此问题,您可以将身份验证数据数据存储在 localStorage 中,并在它为空时为其分配上下文值。

正如 Saba 所指出的,问题在于刷新页面会清除上下文。这是通过以下行完成的:

useEffect(() => {
    if (token['qr-token']) window.location.href = '/settings'
}, [token])

不要在单页应用程序中使用通常的重定向方法。相反,使用

const history = useHistory();
useEffect(() => {
    if (token['qr-token'])
        history.push('/settings');
}, [token])

这不会导致页面重新加载,因此可以使您的上下文保持活动状态。

useContext() provides a dispatch function that has been passed down from the Store component. The dispatch function accepts two arguments, a type of action, and a payload for updating the global state. The useContext() function will then return an updated global state.

const { state, dispatch } = useContext(MyContext);

在您的代码中 setUser 必须使用包含操作类型和负载的参数触发。

例如

setUser({
    type: "SET_USER",
    payload: resp.data
  })