【问题标题】:Using result of useSelector() in component在组件中使用 useSelector() 的结果
【发布时间】:2021-05-05 11:36:21
【问题描述】:

我正在使用 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 个控制台日志一个接一个地出现。第一个为空,第二个为数据。

我在这里缺少什么?这种异步的东西快把我逼疯了!

【问题讨论】:

    标签: reactjs async-await react-redux


    【解决方案1】:

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

    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)
    

    【讨论】:

    • 我这样做的原因是用户不必在每次页面刷新时重新登录。那将是糟糕的用户体验
    【解决方案2】:

    所以创建这样的组件并从本地存储或 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>
        );
    }
    

    【讨论】:

    • 我不确定您是否理解正确...我在本地存储中拥有的唯一东西是 jwt 令牌和刷新令牌。由于商店在刷新时清空,因此我使用刷新令牌生成新令牌并获取用户 ID。在访问 UserProfile 页面时,我使用用户 ID 和令牌来调用 API 并获取用户信息。然后在整个组件中显示。您的建议似乎对此没有帮助。
    猜你喜欢
    • 1970-01-01
    • 2022-12-09
    • 2019-11-29
    • 2021-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-10
    • 1970-01-01
    相关资源
    最近更新 更多