Реакция JS: обработано меньше хуков, чем ожидалось. Это может быть вызвано случайным ранним возвратом - PullRequest
0 голосов
/ 24 января 2020

Я пытаюсь выполнить аутентификацию для проекта React JS, но получаю следующую ошибку:

Оказано меньше хуков, чем ожидалось. Это может быть вызвано случайным ранним возвращением.

Я читал другие вопросы (например, это и это ), но я думаю, что моя ситуация отличается так как я установил все 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>;
};

И тогда это мой 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>
  );
};

Здесь я создал эту песочницу , чтобы воспроизвести ошибку, которая происходит при срабатывании метода login(). Итак, что я делаю не так?

Ответы [ 3 ]

2 голосов
/ 24 января 2020

Переместите ваше состояние под useEffect.

useEffect(() => {})

if (context.token) {
  return <Redirect to="/" />;
}
0 голосов
/ 24 января 2020

Переместите логи перенаправления c после перехвата.

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

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

В вашем домашнем компоненте вы перенаправляете пользователя, если userIsValid идентификатор не true. И это поле всегда будет неопределенным, так как оно не определено в context. Добавьте это поле в контекст и попробуйте.

Надеюсь, что это решит проблему.

0 голосов
/ 24 января 2020

Ошибка из консоли говорит вам, где именно проблема. Вы не можете создавать крючки условно. Этот хук является проблемой и должен появиться перед оператором возврата. Это, вероятно, означает, что вы должны изменить условия загрузки, чтобы работать как положено.

useEffect(() => {
    context.setLoading(false);
}, []);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...