Rubans
Rubans

Reputation: 4478

How to re-render a component based on state changing

I'm trying to redirect to login page if not logged when trying to access any components that require authentication. While trying to use firebase auth, the auth object is not always initialised and there is a small delay so according to documentation, I have to use onAuthStateChanged() event listener which all works ok with the Nav bar which shows the signed in user. However, when trying to to do the redirection for loggedin users, it's not working as the initial login dialog is being shown always as the state for authuser initially is not set and the routing seems to have already taken place. I seen a similar question (Firebase, Avoid Logged-in user to visit login page) here but don't really understand how I can use the suggestion cookies/querystrings from one of the comments when going directly to the url as there will still be small delay initially between the session value being set and rendering so don't see how it will work first time using that way. Totally new to React so hope this question makes sense.

PrivateRoute.js :

    // This is used to determine if a user is authenticated and
// if they are allowed to visit the page they navigated to.

// If they are: they proceed to the page
// If not: they are redirected to the login page.
import React, {useState} from 'react'
import { Redirect, Route } from 'react-router-dom'

const PrivateRoute = ({ loggedInUser, component: Component, ...rest }) => {
  console.log("Private Route, Logged User:"+JSON.stringify(loggedInUser))
  return (
    <Route
      {...rest}
      render={props =>
        (loggedInUser) ? (
          <Component {...props} />
        ) : (
          <Redirect to={{ pathname: '/login', state: { from: props.location } }} />
        )
      }
    />
  )
}
export default PrivateRoute;

Upvotes: 0

Views: 311

Answers (1)

Solijon Sharipov
Solijon Sharipov

Reputation: 179

I have never worked with firebase, but I am doing something like this.

Let's say I have custom hooks, where I am getting my token, login, logout functions.

Here is my app.js looks like. I am getting token if user authorized to access. If access granted it gets the token, then sets the routes and redirects to admin dashboard.

function App() {
  const { token, login, logout } = useAuth();
  let routes;

  if (token) {
    routes = (
      <Switch>
        <Redirect to="/dashboard" />
      </Switch>
    );
  } else {
    routes = (
      <Switch>
        <Redirect to="/login" />
        <Route path="/" exact component={Layout} />
      </Switch>
    )
  }

  return (
    <AuthContext.Provider
      value={{
        isLoggedIn: !!token,
        token: token,
        login: login,
        logout: logout,
      }}
    >
      <Navigation />
      <Router>
        <main>
          {routes}
        </main>
      </Router>
    </AuthContext.Provider>
  );
}

And this how my nav looks like

const Navigation = () => {
  const auth = useContext(AuthContext);

  return (
    <>
      { auth.isLoggedIn && (<AdminNavigation />) }
      { !auth.isLoggedIn && (<UserNavigation />) }
    </>
  );
};

This is how my SignIn component looks like

const SignIn = () => {
  const auth = useContext(AuthContext);
  const classes = useStyles();

  const {
    // eslint-disable-next-line no-unused-vars
    isLoading, error, sendRequest, clearError,
  } = useHttpClient();

  const [password, setPassword] = useState('');
  const [email, setEmail] = useState('');
  const [isLoggedIn, setIsLoggedIn] = useState(true);

  const updateInput = (event) => {
    if (event.target.id.toLowerCase() === 'email') {
      setEmail(event.target.value);
    } else {
      setPassword(event.target.value);
    }
  };

  const handleSwitchMode = () => {
    setIsLoggedIn((prevMode) => !prevMode);
  };

  const authSubmitHandler = async (event) => {
    event.preventDefault();

    setIsLoggedIn(true);
    // auth.login();

    if (isLoggedIn) {
      try {
        const responseData = await sendRequest(
          `${API_URL}/admin/login`,
          'POST',
          JSON.stringify({
            email,
            password,
          }),
          {
            'Content-Type': 'application/json',
          },
        );
        setIsLoggedIn(false);
        auth.login(responseData.token);
      } catch (err) {
        setIsLoggedIn(false);
      }
    } else {
      try {
        const responseData = await sendRequest(
          `${API_URL}/admin/signup`,
          'POST',
          JSON.stringify({
          // name,
            email,
            password,
          }),
          {
            'Content-Type': 'application/json',
          },
        );
        auth.login(responseData.token);
      } catch (err) {
        clearError();
      }
    }
  };


return (
    <Container component="main" maxWidth="xs">
      <div className={classes.paper}>
        <Typography component="h1" variant="h5">
          {isLoggedIn ? 'Login' : 'Sign up'}
        </Typography>
        <form className={classes.form} noValidate>
          {!isLoggedIn && (
            <TextField
              variant="outlined"
              margin="normal"
              required
              fullWidth
              id="name"
              label="Your name"
              autoFocus
              onChange={updateInput}
            />
          )}

          <TextField
            variant="outlined"
            margin="normal"
            required
            fullWidth
            id="email"
            label="Email Address"
            name="email"
            autoComplete="email"
            autoFocus
            value={email}
            onChange={updateInput}
          />
          <TextField
            variant="outlined"
            margin="normal"
            required
            fullWidth
            name="password"
            label="Password"
            type="password"
            id="password"
            value={password}
            autoComplete="current-password"
            onChange={updateInput}
          />
          <FormControlLabel
            control={<Checkbox value="remember" color="primary" />}
            label="Remember me"
          />
          <Button
            type="submit"
            fullWidth
            variant="contained"
            color="primary"
            className={classes.submit}
            onClick={authSubmitHandler}
          >
            {isLoggedIn ? 'Login' : 'Sign up'}
          </Button>
          <Grid container>
            <Grid item xs>
              <Link href="/" variant="body2">
                Forgot password?
              </Link>
            </Grid>
            <Grid item>
              <Button
                onClick={handleSwitchMode}
              >
                Dont have an account? Sign Up
              </Button>
            </Grid>
          </Grid>
        </form>
      </div>
    </Container>
  );

Hope this helps.

Upvotes: 1

Related Questions