Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React-Redux how to prevent page from rendering before redirect

Tags:

I'm working on a personal project and I have trouble with checking if a user is logged in or not so that when they try to go to /login, it'll redirect them to the home page. Currently what my code does is the following:

  1. Defined my own Route components
  2. When checkIfSignedIn is called, it dispatches actions that set the isLoggedIn state to either True or False.
  3. The AuthenticatedRouter component checks if the store's isLoggedIn state is true or false and will either render the component or redirect to home.
  4. This works, but the issue is that isLoggedIn is initially false, so if they are logged in, the login form shows up for a second and then redirects after isLoggedIn becomes true.

I can't figure out how to fix the problem with rendering the component with the default state and then suddenly redirects because the state changes. Thanks

  • I'm using firebase for the user account.

Routes.js

const Routes = (props) => {
    props.checkIfSignedIn();
    return(
        <Router>
            <Switch>
                <Route exact path='/' component={App}/>
                <AuthorizedRoute path="/signup" component={SignUp}/>
                <AuthorizedRoute path="/signin" component={SignIn}/>
                <Route component={InvalidPage}/>
            </Switch>
        </Router>
    );
};

const mapDispatchToProps = (dispatch) => {
    return{
        checkIfSignedIn: () => dispatch(checkIfSignedIn())
    };
};

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

AuthorizedRoute.js

class AuthorizedRoute extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            isLoggedIn: false
        };
    };

    render(){
        const { component: Component, ...rest } = this.props;
        return(
            <Route {...rest} render={props => {
                if (this.props.isLoggedIn){
                    console.log(this.state.isLoggedIn);
                    return <Redirect to="/" />
                } else{
                    return <Component {...props} />
                }
            }} />
        );
    }
};


const mapStateToProps = (state) => {
    return{
        isLoggedIn : state.authentication.isLoggedIn
    };
};

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

authentication.js - action creators

const setSignedInFalse = () => {
    return{
        type: IS_SIGNED_IN_FALSE
    };
};

const setSignedInTrue = () => {
    return{
        type: IS_SIGNED_IN_TRUE
    };
};

const checkIfSignedIn = () => {
    return dispatch => {
        firebaseApp.auth().onAuthStateChanged(user => {
            if (user){
                dispatch(setSignedInTrue());
            } else{
                dispatch(setSignedInFalse());
            }
        });
    };
};

export default checkIfSignedIn;

authentication.js - reducer

const defaultState = {
    isLoggedIn: false
};

const authentication = (state = defaultState, action) => {
    let authenticationState = null;
    switch (action.type){
        case IS_SIGNED_IN_FALSE:
            authenticationState = {
                isLoggedIn: false
            };
            return authenticationState;
        case IS_SIGNED_IN_TRUE:
            authenticationState = {
                isLoggedIn: true
            };
            return authenticationState;
        default:
            return state;
    };
};

export default authentication;

Hacky solution (Not sure if this is frowned upon).

I set my Auth reducer's default state, isLoggedIn : null instead of false. Then in my AuthorizedRoute component I now have 3 conditions to render null first and then either the component or redirect.

//AuthorizedRoute Component
if (this.props.isLoggedIn){
    return <Redirect to="/" />
} else if (this.props.isLoggedIn === false){
    return <Component {...props} />
} else{
    return null;
}
like image 820
Justin Avatar asked Dec 20 '17 08:12

Justin


People also ask

How do I stop re-rendering in React redux?

Options for preventing re-renders One popular method for preventing re-renders is using Selectors in React Redux, which are functions that subscribe to the Redux store and run whenever an action is dispatched. Selectors use === as a strict quality check, re-rendering the component whenever data is changed.

How do I stop unnecessary rendering in React?

1. Memoization using useMemo() and UseCallback() Hooks. Memoization enables your code to re-render components only if there's a change in the props. With this technique, developers can avoid unnecessary renderings and reduce the computational load in applications.

How do you prevent a child component from re-rendering React?

OR, we can remove function memoization here, and just wrap ChildComponent in React. memo : MovingComponent will re-render, “children” function will be triggered, but its result will be memoized, so ChildComponent will never re-render.

How do I stop infinite rendering in React?

To get rid of your infinite loop, simply use an empty dependency array like so: const [count, setCount] = useState(0); //only update the value of 'count' when component is first mounted useEffect(() => { setCount((count) => count + 1); }, []); This will tell React to run useEffect on the first render.


1 Answers

What you may do is something like this: (in your auth reducer).

let user = JSON.parse(localStorage.getItem('user'));
const initialState = user ? { isLoggedIn: true } : {};

Also you had to set the localstorage when your user is logging in and remove it when he is logging out.

like image 180
Fabien Greard Avatar answered Nov 23 '22 06:11

Fabien Greard