简体   繁体   English

使用钩子响应 Redux - 身份验证和受保护的路由

[英]React Redux with hooks - authentication and protected routes

I am using React with hooks, react-redux and redux-thunk and I'm not sure if I made the authentication correctly.我正在使用带有钩子、react-redux 和 redux-thunk 的 React,我不确定我是否正确进行了身份验证。 In Main.js I'm calling an action called checkIfLoggedIn() .在 Main.js 中,我正在调用一个名为checkIfLoggedIn() This is the Main.js content:这是 Main.js 的内容:

class Main extends React.Component {
    constructor(props) {
        super(props);
        this.props.checkIfLoggedIn();

    }

    render() {
        return (
            <BrowserRouter>
                <div style={{position: 'relative'}}>
                    <Navbar/>
                    <div className={'container-fluid'}>
                        <Route exact path={'/'} component={(Dashboard)}/>
                        <Route exact path={'/sale'} component={(Sale)}/>
                        <Route exact path={'/settings'} component={(Settings)}/>
                        <Route exact path={'/login'} component={(Login)}/>
                    </div>
                </div>
            </BrowserRouter>
        )
    }
}

const mapDispatchToProps = {
    checkIfLoggedIn
};

export default connect(null, mapDispatchToProps)(Main);

This is the code of checkIfLoggedIn()这是checkIfLoggedIn()的代码

import {SET_ADMIN, SET_LOGGED_IN} from "./types";
import axios from 'axios';

export const checkIfLoggedIn = () => async dispatch => {
    const adminToken = window.localStorage.getItem('admin_token');
    if (adminToken === null)
        dispatch({
            type: SET_LOGGED_IN,
            payload: false
        });
    else {
        try {
            const r = await axios.get('/users/me');
            const data = r.data;
            dispatch({
                type: SET_ADMIN,
                payload: data
            });
            dispatch({
                type: SET_LOGGED_IN,
                payload: true
            });

        } catch (e) {
            dispatch({
                type: SET_LOGGED_IN,
                payload: false
            });
        }
    }
};

And my initial state:而我的初始状态:

const initialState = {
    isLoggedIn: false,
    currentAdmin: {
    },
};

Now, I'd like to make a ProtectedRoute that will Redirect me to the Login route when I'm not logged in. I wanted to make something similar in the Login component, that would Redirect me to the '/' route if I'm logged in.现在,我想提出一个ProtectedRoute将重定向我的登录路由时,我没有登录。我想使在登录组件类似的东西,那会重定向我的'/'如果我”路线我登录了。

But in both cases, my prop isLoggedIn is initially set to false, and gets updated after few milliseconds.但在这两种情况下,我的道具 isLoggedIn 最初都设置为 false,并在几毫秒后更新。 This is my Login component code that didn't work as expected:这是我没有按预期工作的登录组件代码:

const Login = props => {

    const dispatch = useDispatch();
    const [redirect, setRedirect] = useState(false);

    dispatch(checkIfLoggedIn());

    useEffect(() => {
            setRedirect(props.isLoggedIn);

    }, [props.isLoggedIn]);

    return redirect ? <Redirect to={'/'} /> : (
    /* the login form code */
    )
}

The form is displayed for a moment, and after that I'm redirected to the main route.表单显示片刻,然后我被重定向到主路由。 How can I prevent displaying the form?如何防止显示表单? And how can I make a PrivateRoute waiting a moment to receive all the props and getting the initial isLoggedIn status?以及如何让 PrivateRoute 等待片刻以接收所有道具并获得初始 isLoggedIn 状态?

Not sure I completely understand the context of what you are doing, but here are my thoughts.不确定我是否完全理解你在做什么,但这是我的想法。 In your useEffect, the isLoggedIn boolean seems to be controlling the redirect boolean, which may be causing unwanted side effects.在您的 useEffect 中, isLoggedIn 布尔值似乎正在控制重定向布尔值,这可能会导致不必要的副作用。

Try this instead试试这个

const Login = props => {

    const dispatch = useDispatch();
    const [redirect, setRedirect] = useState(false);

    dispatch(checkIfLoggedIn());

    useEffect(() => {
            // If user is not logged in, redirect them
            if (!props.isLoggedIn) {
            setRedirect(true)
     }

    }, [props.isLoggedIn]);

    return redirect ? <Redirect to={'/'} /> : (
    /* the login form code */
    )
}

If you are using react-router, and you export this component usint the withRouter higher order component, it may be better to use history.push for what you are trying to accomplish如果您使用的是 react-router,并且您使用withRouter高阶组件导出此组件,则最好使用history.push来完成您要完成的任务

const Login = props => {

    const dispatch = useDispatch();
    const [redirect, setRedirect] = useState(false);

    dispatch(checkIfLoggedIn());

    useEffect(() => {
            // If user is not logged in, redirect them
            if (!props.isLoggedIn) {
            props.history.push('/redirectRoute')
     }

    }, [props.isLoggedIn]);

    return redirect ? <Redirect to={'/'} /> : (
    /* the login form code */
    )
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM