Home > OS >  React Redux and state after refresh
React Redux and state after refresh

Time:12-01

I have a problem with understanding why my app works kinda odd. When I try to reach any site on my page by clicking a link button in navbar, it navigates me there without any problems, like when I click "My account", the URL changes to "http://localhost:3000/my_account" and everything works just fine. In this place I have to mention that "/my_account" is a protected route - user has to be logged in to reach it, when he is not logged in - he gets send to the homepage. So now the problem is that when user is logged in and tries to reach the protected route like "http://localhost:3000/my_account" by entering this URL and loading page - he is treated like a non-logged user and gets redirected to the homepage. And after he is redirected there and tries to reach this site by clicking the navbar link, he can enter this page - he is logged in. My expected result is that user can enter any URL on the site and react should check PROPRERLY if he is logged in in both cases - either when clicking a link on site or by providing a url. Can anyone tell me where do I make mistake?

UserAccount (/my_account) is a simple component:

import React, { Component } from 'react'

export class UserAccount extends Component {
    render() {
        return (
            <div>
                UserAccount
            </div>
        )
    }
}

export default UserAccount

In router in App.js I declare this route as:

<PrivateRoute path="/my_account" exact component={UserAccount}></PrivateRoute>

And the PrivateRoute is a functional component:

import React from 'react'
import {Route, Redirect} from 'react-router-dom'
import {connect} from 'react-redux'


const PrivateRoute = ({component : Component, auth, ...rest}) => (
    <Route {...rest} render={props => {
        if(auth.isLoading){
            return <h2>LOADING ...</h2>
        }
        else if(!auth.isAuthenticated){
            return <Redirect to="/login"></Redirect>
        }
        else{
        return <Component {...props}/>
        }
    
    }}></Route>
)
    


const mapStateToProps = state =>({
auth: state.auth
})

export default connect(mapStateToProps,null)(PrivateRoute);

My state in auth.js (reducer):

const initialState = {
    access: localStorage.getItem('access'),
    refresh: localStorage.getItem('refresh'),
    isAuthenticated: null,
    isLoading : false,
    user: null,
    requestSent: false,
    payload: null,
    message: null
}

And after successful login, state changes as follows:

    switch(type){
        case AUTHENTICATED_SUCCESS:
            return {
                ...state,
                isAuthenticated: true
            } 
        case LOGIN_SUCCESS:
            localStorage.setItem('access', payload.access);
            return{
                ...state,
                isAuthenticated: true,
                access: payload.access,
                refresh: payload.refresh
            }

And login function from auth.js actions:

export const login = (email, password) => async dispatch =>{
    const config = {
        headers: {
            'Content-Type': 'application/json'
        }
    };
    
    const body = JSON.stringify({email, password});

    try{
        const res = await axios.post(`${process.env.REACT_APP_API_URL}/auth/jwt/create/`, body, config);
        dispatch({
            type: LOGIN_SUCCESS,
            payload: res.data
        })
        dispatch(load_user());
        dispatch(createMessage({logged_in_successfully: "You are now logged in."}))
    } catch (err) {
        dispatch({
            type: LOGIN_FAIL,
            payload: err
        })
        const errors =  {msg: err.response.data, status: err.response.status}
        dispatch({
            type:GET_ERRORS,
            payload: errors
        })
    }
};

Thanks for your time reading that and I am hoping for some help.

CodePudding user response:

import React, { useEffect } from 'react'
import { useNavigate } from 'react-router-dom'

export default function UserAccount() {
    let navigate = useNavigate();
    useEffect(() => {
        let authToken = sessionStorage.getItem('access')
     
        // if user is not authed, redirect user to login page
        if (!authToken) {
            navigate('/login')
        }

     }, [])
    return (
        <div>
            Home Page
        </div>
    )
}

Answer uses functional component and react router v6 . If you provide which version of react-router you're using I can update my answer

You forgot to add condition for checking weather user is authed or no. For this, you need to check inside UserAccount Page. I provided snippet. Condition should be write inside useEffect in functional component. Inside class based component inside componentDidMount. More about authentication can be found here

Besides that, you should also add condition inside Login page and Register page. To protect user from reregistering and re-logining again.

CodePudding user response:

Well probably I found a solution. Since I am setting a null value in a store as default, I've changed my PrivateRoute code to check if it is null, if it is, we wait with rendering or redirecting until it becomes true or false:

import React from 'react'
import {Route, Redirect} from 'react-router-dom'
import {connect} from 'react-redux'


const PrivateRoute = ({component : Component, auth, ...rest}) => (
    <Route {...rest} render={props => {
        if(auth.isLoading){
            return <h2>LOADING ...</h2>
        }
        else if(auth.isAuthenticated==null){
            return <h2>LOADING ...</h2>
        }
        else if(auth.isAuthenticated==false){
            return <h2>Not authenticated ... redirecting here</h2>
        }
        else{
        return <Component {...props}/>
        }
    
    }}></Route>
)

const mapStateToProps = state =>({
auth: state.auth,
})

export default connect(mapStateToProps,null)(PrivateRoute);

Can anyone tell me if it is a good or bad idea?

  • Related