简体   繁体   English

如何根据状态变化重新渲染组件

[英]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.在尝试使用 firebase auth 时,auth 对象并不总是初始化并且有一个小的延迟,因此根据文档,我必须使用 onAuthStateChanged() 事件侦听器,它与显示已登录用户的导航栏一起工作正常。 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.但是,当尝试为登录用户进行重定向时,它不起作用,因为初始登录对话框始终显示,因为最初未设置 authuser 的状态并且路由似乎已经发生。 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.我在这里看到了一个类似的问题( Firebase,避免登录用户访问登录页面),但我不太明白在直接转到 url 时如何使用其中一个评论中的建议 cookie/querystrings,因为仍然会有最初设置会话值和渲染之间的延迟很小,因此第一次使用这种方式时看不到它是如何工作的。 Totally new to React so hope this question makes sense.对 React 来说是全新的,所以希望这个问题是有道理的。

PrivateRoute.js : 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;

I have never worked with firebase, but I am doing something like this.我从未与 firebase 合作过,但我正在做这样的事情。

Let's say I have custom hooks, where I am getting my token, login, logout functions.假设我有自定义钩子,我可以在其中获取令牌、登录、注销功能。

Here is my app.js looks like.这是我的 app.js 的样子。 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这就是我的 SignIn 组件的样子

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.希望这可以帮助。

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

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