React JS:渲染的钩子比预期的少。这可能是由于意外的提前退货声明造成的

Mar*_*mal 1 javascript state reactjs react-context

我正在尝试对 React JS 项目进行身份验证,但是出现以下错误:

呈现的钩子比预期的少。这可能是由意外的提前退货声明引起的。

我正在阅读其他问题(如thisthis),但我想我的情况有所不同,因为我useState在创建组件后设置了所有。

我使用了不同的方法来完成这项工作,但它们都不适合我。

我在ContextWrapper组件中添加了这样的方法:

import React, { useState, useEffect } from "react";
import { useCookies } from "react-cookie";
import jwt from "jsonwebtoken";
import { fetchLogin, fetchVerify } from "../fake-server";
import Context from "./context";

export default ({ children }) => {
  const [token, setToken] = useState(null);
  const [message, setMessage] = useState(null);
  const [loading, setLoading] = useState(false);
  const [cookies, setCookie, removeCookie] = useCookies(["token"]);

  useEffect(() => {
    console.log(cookies);
    if (cookies.token) {
      setToken(cookies.token);
    }
  }, []);

  useEffect(() => {
    if (token) {
      setCookie("token", JSON.stringify(token), { path: "/" });
    } else {
      removeCookie("token");
    }

    console.log(token);
  }, [token]);

  function login(email, password) {
    fetchLogin(email, password)
      /*.then(response => response.json())*/
      .then(data => {
        const decoded = jwt.decode(data.token);
        const token = {
          token: data.token,
          ...decoded
        };
        setToken(token);
      })
      .catch(error => {
        console.log("error", error);
        setMessage({
          status: 500,
          text: error
        });
      });
  }

  function verify() {
    fetchVerify(cookies.token)
      /*.then(response => response.json())*/
      .then(data => {
        setToken(data);
      })
      .catch(error => {
        setToken(null);
        setMessage({
          status: 500,
          text: error
        });
      });
  }

  function logout() {
    setToken(false);
  }

  const value = {
    login,
    verify,
    logout,
    token,
    message,
    setMessage,
    loading,
    setLoading
  };

  return <Context.Provider value={value}>{children}</Context.Provider>;
};
Run Code Online (Sandbox Code Playgroud)

然后这是我的Login组件:

import React, { useState, useContext, useEffect } from "react";
import {
  Grid,
  Card,
  Typography,
  CardActions,
  CardContent,
  FormControl,
  TextField,
  Button
} from "@material-ui/core";
import { Redirect } from "react-router-dom";
import { makeStyles } from "@material-ui/core/styles";
import Context from "../context/context";

const useStyles = makeStyles(theme => ({
  root: {
    height: "100vh",
    display: "flex",
    justifyContent: "center",
    alignContent: "center"
  },
  title: {
    marginBottom: theme.spacing(2)
  },
  card: {},
  formControl: {
    marginBottom: theme.spacing(1)
  },
  actions: {
    display: "flex",
    justifyContent: "flex-end"
  }
}));

export default ({ history, location }) => {
  const context = useContext(Context);
  const classes = useStyles();
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  if (context.token) {
    return <Redirect to="/" />;
  }

  useEffect(() => {
    context.setLoading(false);
  }, []);

  function onSubmit(e) {
    e.preventDefault();
    context.login(email, password);
  }

  return (
    <Grid container className={classes.root}>
      <Card className={classes.card}>
        <form onSubmit={onSubmit}>
          <CardContent>
            <Typography variant="h4" className={classes.title}>
              Login
            </Typography>
            <FormControl className={classes.formControl} fullWidth>
              <TextField
                type="text"
                variant="outlined"
                label="Email"
                value={email}
                onChange={e => setEmail(e.target.value)}
              />
            </FormControl>
            <FormControl className={classes.formControl} fullWidth>
              <TextField
                type="password"
                variant="outlined"
                label="Password"
                value={password}
                onChange={e => setPassword(e.target.value)}
              />
            </FormControl>
          </CardContent>
          <CardActions className={classes.actions}>
            <Button type="submit" variant="contained" color="secondary">
              Login
            </Button>
          </CardActions>
        </form>
      </Card>
    </Grid>
  );
};
Run Code Online (Sandbox Code Playgroud)

在这里我创建了这个沙箱来重现login()触发方法时发生的错误。那么,我做错了什么?

Asa*_*viv 5

将您的条件移到useEffect.

useEffect(() => {})

if (context.token) {
  return <Redirect to="/" />;
}
Run Code Online (Sandbox Code Playgroud)