在组件中使用 useSelector() 的结果

时间:2021-02-01 09:32:58

标签: reactjs async-await react-redux

我使用 react-redux 管理状态,使用 axios 进行 API 调用。

我的默认状态:

const defaultState = {
    isLoading: true,
    isAuthenticated: false,
    authUser: {}
}
一旦 API 的登录调用成功运行,

isLoadingauthUser 都会更新。这里没有错。

在 userProfile 组件中,我使用以下内容从商店获取登录用户的 ID:

const authUser = useSelector(state => state.authentication.authUser);

const user = users.getUser(authUser.id);
console.log(authUser);

authUser 在页面加载时始终为空,但会延迟一秒钟,它再次打印,这次是状态内容。

我在自定义 PrivateRoute 组件后面有 userProfile 组件:

const PrivateRoute = ({ component: Component, ...rest }) => {
    const authentication = useSelector(state => state.authentication);
    
    return (
        <Route
            {...rest}
            render={props =>
                authentication.isAuthenticated ? (
                    <Component {...props} />
                ) : (
                    authentication.isLoading ? 'loading...' :
                        <Redirect to={{ pathname: '/login', state: { from: props.location } }} />
                )
            }
        />
    )
};

loading... 文本在组件赶上之前显示,然后 2 个控制台日志一个接一个出现。第一个是空的,第二个是数据。

我在这里错过了什么?这种异步的东西让我发疯!

2 个答案:

答案 0 :(得分:0)


通过私有路由的这种实现,你可以保存用户的当前路径,让用户再次登录后继续他的过程

import React from 'react';
import { Login } from '../../pageComponents';
import { useSelector } from 'react-redux';

const PrivateRoute = (Component) => {
const Auth = (props) => {
    const { isLoggedIn } = useSelector((state) => state.user);
    // Login data added to props via redux-store (or use react context for example)
    // If user is not logged in, return login componentc
    if (!isLoggedIn) {
        return <Login />;
    }
    // If user is logged in, return original component
    return <Component {...props} />;
};

// Copy getInitial props so it will run as well
if (Component.getInitialProps) {
    Auth.getInitialProps = Component.getInitialProps;
}

return Auth;
};

export default PrivateRoute;

然后在每个你想要 Private Rout 的页面使用它,如下所示

const myPrivateRoute = () => {
    return (
        <h1>Hello world</h1>
     )
}

export default PrivateRoute(myPrivateRoute)

答案 1 :(得分:0)


所以创建这样的组件并从本地存储或cookie加载你的最后一部分然后验证并发送到你的redux存储然后你可以记住日志

import { useEffect, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import axios from "axios";
import * as globalActions from "../../../store/actions/globalAction";
import * as userAction from "../../../store/actions/userAction";
const StorageManagment = () => {
const dispatch = useDispatch();
/* ----------------------------------- listening to token changes ----------------------------------- */

useEffect(() => {
    dispatch(userAction.loadCart());
}, []);
useEffect(async () => {
    try {
        if (window)
            await checkLocalDataWithRedux()
                .then((data) => {
                    const { userDTO, token } = data;
                    dispatch(userAction.loginUser(token, userDTO));
                })
                .catch((e) => {
                    console.log(e);
                    dispatch(userAction.logOutUser());
                });
    } catch (e) {
        throw e;
    }
}, []);

function checkLocalDataWithRedux() {
    return new Promise((resolve, reject) => {
        try {
            /* -------- read user data from localStorage and set into redux store ------- */
            const { userDTO, token } = localStorage;
            if (userDTO && token) {
                resolve({ token: token, userDTO: JSON.parse(userDTO) });
            } else logOutUser();
        } catch (e) {
            reject();
        }
    });
}

function logOutUser() {
    dispatch(userAction.logOutUser());
}

return null;
};

export default StorageManagment;

然后将其加载到您的 app.jsx 文件中

app.js

render() {
    return (
        <React.Fragment>
            <Provider store={store}>
                <ErrorBoundary>
                    <StorageManagment />
                    <DefaultLayout>
                        <Application {...this.props} />
                    </DefaultLayout>
                </ErrorBoundary>
            </Provider>
        </React.Fragment>
    );
}