【问题标题】:Maximum update depth exceeded with useEffect & mapuseEffect & map 超过了最大更新深度
【发布时间】:2021-06-30 21:04:55
【问题描述】:

我在尝试设置表单错误对象时遇到了这个问题。基本上,我想在每个输入字段下方显示错误。作为回应,我得到了一个对象数组,如何设置我的错误对象?

错误 - 超出最大更新深度。当组件在 useEffect 中调用 setState 时,可能会发生这种情况,但 useEffect 要么没有依赖数组,要么每次渲染时其中一个依赖项都发生了变化。

import axios from "axios";
import React, { useState, useEffect, useCallback } from "react";
import { Link } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { register } from "../actions/userActions";
const Register = () => {
    const [countriesList, setCountriesList] = useState("");
    const [userRegistration, setUserRegistration] = useState({
        firstName: "",
        lastName: "",
        email: "",
        password: "",
        fullAddress: "",
        city: "",
        zipCode: "",
        country: "",
        phone: "",
        terms: true,
    });
    const [userRegistrationError, setUserRegistrationError] = useState({
        firstNameError: "",
        lastNameError: "",
        emailError: "",
        passwordError: "",
        fullAddressError: "",
        cityError: "",
        zipCodeError: "",
        countryError: "",
        phoneError: "",
        termsError: "",
    });
    const dispatch = useDispatch();

    const userRegister = useSelector((state) => state.userRegister);
    const { loading, errors, success } = userRegister;

    useEffect(() => {
        const countries = async () => {
            try {
                const { data } = await axios.get(
                    `https://restcountries.eu/rest/v2/all`
                );
                setCountriesList(data);
            } catch (err) {
                console.error(err);
            }
        };
        countries();
    }, []);

    useEffect(() => {
        const handleErrors = (errors) => {
            errors.map((error) => {
                if (error.param === "firstname") {
                    setUserRegistrationError({
                        ...userRegistrationError,
                        firstNameError: error.msg,
                    });
                }
                if (error.param === "email") {
                    setUserRegistrationError({
                        ...userRegistrationError,
                        emailError: error.msg,
                    });
                }
                return null;
            });
        };
        if (errors) {
            handleErrors(errors);
        }
    }, [errors, setUserRegistrationError]);

    const handleChange = (e) => {
        const name = e.target.name;
        const value = e.target.value;
        setUserRegistration({ ...userRegistration, [name]: value });
    };
    const handleChkChange = (e) => {
        const checked = e.target.checked;
        console.log(checked);
        setUserRegistration({ ...userRegistration, terms: checked });
    };

    const handleSubmit = (e) => {
        e.preventDefault();
        try {
            dispatch(register());
        } catch (error) {
            console.error(error);
        }
    };
    return (
        <div className="form_container">
            <form action="" onSubmit={handleSubmit}>
                <div className="row no-gutters">
                    <div className="col-6 pr-1">
                        <div className="form-group">
                            <div className="form-group">
                                <input
                                    type="text"
                                    name="firstName"
                                    className="form-control"
                                    placeholder="First Name*"
                                    value={userRegistration.firstName}
                                    onChange={handleChange}
                                />
                                <p className="form-vald-error">
                                    {userRegistrationError.firstNameError &&
                                        userRegistrationError.firstNameError}
                                </p>
                            </div>
                        </div>
                    </div>
                    <div className="col-6 pr-1">
                        <div className="form-group">
                            <input
                                type="text"
                                className="form-control"
                                name="lastName"
                                placeholder="Last Name*"
                                value={userRegistration.lastName}
                                onChange={handleChange}
                            />
                            <p className="form-vald-error">
                                {userRegistrationError.lastNameError &&
                                    userRegistrationError.lastNameError}
                            </p>
                        </div>
                    </div>
                </div>
                <hr />
                <div className="private box">
                    <div className="row no-gutters">
                        <div className="col-6 pr-1">
                            <div className="form-group">
                                <input
                                    type="email"
                                    className="form-control"
                                    name="email"
                                    id="email_2"
                                    placeholder="Email*"
                                    value={userRegistration.email}
                                    onChange={handleChange}
                                />
                                <p className="form-vald-error">
                                    {userRegistrationError.emailError &&
                                        userRegistrationError.emailError}
                                </p>
                            </div>
                        </div>
                        <div className="col-6 pl-1">
                            <div className="form-group">
                                <input
                                    type="password"
                                    className="form-control"
                                    name="password"
                                    id="password_in_2"
                                    placeholder="Password*"
                                    value={userRegistration.password}
                                    onChange={handleChange}
                                />
                                <p className="form-vald-error">
                                    {userRegistrationError.passwordError &&
                                        userRegistrationError.passwordError}
                                </p>
                            </div>
                        </div>
                        <div className="col-12">
                            <div className="form-group">
                                <input
                                    type="text"
                                    name="fullAddress"
                                    className="form-control"
                                    placeholder="Full Address*"
                                    value={userRegistration.fullAddress}
                                    onChange={handleChange}
                                />
                                <p className="form-vald-error">
                                    {userRegistrationError.fullAddressError &&
                                        userRegistrationError.fullAddressError}
                                </p>
                            </div>
                        </div>
                    </div>
                    {/* /row */}
                    <div className="row no-gutters">
                        <div className="col-6 pr-1">
                            <div className="form-group">
                                <input
                                    type="text"
                                    className="form-control"
                                    placeholder="City*"
                                    name="city"
                                    value={userRegistration.city}
                                    onChange={handleChange}
                                />
                                <p className="form-vald-error">
                                    {userRegistrationError.cityError &&
                                        userRegistrationError.cityError}
                                </p>
                            </div>
                        </div>
                        <div className="col-6 pl-1">
                            <div className="form-group">
                                <input
                                    type="text"
                                    className="form-control"
                                    placeholder="Postal Code*"
                                    name="zipCode"
                                    value={userRegistration.zipCode}
                                    onChange={handleChange}
                                />
                                <p className="form-vald-error">
                                    {userRegistrationError.zipCodeError &&
                                        userRegistrationError.zipCodeError}
                                </p>
                            </div>
                        </div>
                    </div>
                    {/* /row */}
                    <div className="row no-gutters">
                        <div className="col-6 pr-1">
                            <div className="form-group">
                                <div className="custom-select-form">
                                    <select
                                        className="wide add_bottom_10 form-control"
                                        name="country"
                                        id="country"
                                        value={userRegistration.country}
                                        onChange={handleChange}
                                    >
                                        <option>Country*</option>
                                        {countriesList &&
                                            countriesList.map((country) => (
                                                <option
                                                    key={country.alpha2Code}
                                                    value={country.alpha2Code}
                                                >
                                                    {country.name}
                                                </option>
                                            ))}
                                    </select>
                                    <p className="form-vald-error">
                                        {userRegistrationError.countryError &&
                                            userRegistrationError.countryError}
                                    </p>
                                </div>
                            </div>
                        </div>
                        <div className="col-6 pl-1">
                            <div className="form-group">
                                <input
                                    type="text"
                                    className="form-control"
                                    placeholder="Telephone *"
                                    name="phone"
                                    value={userRegistration.phone}
                                    onChange={handleChange}
                                />
                                <p className="form-vald-error">
                                    {userRegistrationError.phoneError &&
                                        userRegistrationError.phoneError}
                                </p>
                            </div>
                        </div>
                    </div>
                    {/* /row */}
                </div>
                <hr />
                <div className="form-group">
                    <label className="container_check">
                        Accept <Link to="#0">Terms and conditions</Link>
                        <input
                            type="checkbox"
                            name="terms"
                            checked={userRegistration.terms}
                            onChange={handleChkChange}
                        />
                        <span className="checkmark" />
                        <p className="form-vald-error">
                            {userRegistrationError.termsError &&
                                userRegistrationError.termsError}
                        </p>
                    </label>
                </div>
                <div className="text-center">
                    <input
                        type="submit"
                        defaultValue="Register"
                        className="btn_1 full-width"
                    />
                </div>
            </form>
        </div>
    );
};

export default Register;

【问题讨论】:

  • 我们需要看看 JSX,它会对我们有所帮助。
  • jsx 没有问题,只有第二个 useEffect 导致了这个问题,但我不知道如何解决它

标签: javascript reactjs react-redux react-hooks


【解决方案1】:

你的第二个useEffect有问题,第一次更新你的状态userRegistrationError,组件重新渲染并重新执行了useEffect,因为依赖userRegistrationError 已更改,并且该过程再次重复,因为每次渲染都会更新状态。

 useEffect(() => {
        const handleErrors = (errors) => {
            errors.map((error) => {
                if (error.param === "firstname") {
                    setUserRegistrationError({
                        ...userRegistrationError,
                        firstNameError: error.msg,
                    });
                }
                if (error.param === "email") {
                    setUserRegistrationError({
                        ...userRegistrationError,
                        emailError: error.msg,
                    });
                }
                return null;
            });
        };
        if (errors) {
            handleErrors(errors);
        }
    }, [errors, setUserRegistrationError ]); //replace userRegistrationError by setUserRegistrationError

【讨论】:

  • 我得到了那部分,但我是新手,不知道如何解决它。我尝试在外面定义handleErrors,但它不起作用。你能帮忙吗?
  • 看看我的答案 用 [errors, setUserRegistrationError] 替换 [errors, userRegistrationError]
  • 我没有看到,但它不起作用 eslint 正在抱怨。我正在添加整个代码
  • 忽略 eslint 并使用 [errors, setUserRegistrationError] 测试您的代码。
  • 我已经尝试过您的编辑,但它现在无法正常运行,它没有无限运行,而是设置了最后一个错误值,即电子邮件而不是名字和电子邮件
【解决方案2】:

您的效果取决于userRegistrationError,它是一个基于引用的对象。每次useEffect运行,setUserRegistrationError 创建一个新的对象引用,这会导致无限循环,因为引用不会与前一个相同。

避免此问题并保留正确引用的一种方法是将回调函数传递给setUserRegistrationError,而不是传递一个值。这样userRegistrationError 就不再是依赖项了,而是作为函数的参数:

useEffect(() => {
    const handleErrors = (errors) => {
        errors.forEach((error) => {
            if (error.param === "firstName") {
                // here you pass a callback function instead, and userRegistrationError is no longer a dependency
                // and returns the next state as expected
                setUserRegistrationError(userRegistrationError => ({
                    ...userRegistrationError,
                    firstNameError: error.msg,
                }));
            }
            if (error.param === "email") {
                setUserRegistrationError(userRegistrationError => ({
                    ...userRegistrationError,
                    emailError: error.msg,
                }));
            }
        });
    };
    if (errors) {
        handleErrors(errors);
    }
}, [errors, setUserRegistrationError]);

【讨论】:

  • 我已经尝试过您的编辑,但它现在无法正常运行,它没有无限运行,而是设置了最后一个错误值,即电子邮件而不是名字和电子邮件
  • 我认为问题是名字应该是驼峰式firstName 给定您的输入,对吗? fwiw 你应该使用forEach 而不是map 当你只是迭代一个数组时
  • 参数没有问题看起来像在 set 函数中我必须这样写 (userRegistrationError) => ({ ...userRegistrationError, firstNameError: error.msg, })
  • @NeerajMishra 很好,但这正是我首先发布答案的方式......
  • 我在回答时告诉过要传递一个函数(它也在代码中),我相信你可能没有看到
猜你喜欢
  • 2023-02-07
  • 2022-01-17
  • 1970-01-01
  • 2022-01-16
  • 2020-01-04
  • 1970-01-01
  • 2020-05-24
  • 2020-02-29
  • 2021-07-12
相关资源
最近更新 更多