Ошибка «Превышена максимальная глубина обновления. Это может произойти, когда компонент вызывает setState внутри useEffect» - PullRequest
0 голосов
/ 04 августа 2020

Я сталкиваюсь с этой ошибкой (повторяется тысячи раз, пока не произойдет сбой страницы) всякий раз, когда вызывается мой компонент корзины (также показанный ниже):

index.js:1 Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
    in Cart (created by Context.Consumer)
    in Route (at Routes.js:24)
    in Switch (at Routes.js:23)
    in Router (created by BrowserRouter)
    in BrowserRouter (at Routes.js:22)
    in Routes (at src/index.js:5)

компонент Моя корзина:

import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import Layout from "./Layout";
import { getCart } from "./cartHelpers";
import Card from "./Card";
import Checkout from "./Checkout";

const Cart = () => {
    const [items, setItems] = useState([]);

    useEffect(() => {
        setItems(getCart());
    }, [items]);

    const showItems = items => {
        return (
            <div>
                <h2>Your cart has {`${items.length}`} items</h2>
                <hr />
                {items.map((product, i) => (
                    <Card
                        key={i}
                        product={product}
                        showAddToCartButton={false}
                        cartUpdate={true}
                        showRemoveProductButton={true}
                    />
                ))}
            </div>
        );
    };

    const noItemsMessage = () => (
        <h2>
            Your cart is empty. <br /> <Link to="/shop">Continue shopping</Link>
        </h2>
    );

    return (
        <Layout
            className="container-fluid"
        >
            <div className="row">
                <div className="col-6">
                    {items.length > 0 ? showItems(items) : noItemsMessage()}
                </div>

                <div className="col-6">
                    <h2 className="mb-4">Your cart summary</h2>
                    <hr />
                    <Checkout products={items} />
                </div>
            </div>
        </Layout>
    );
};

export default Cart;

useEffect вызывает getCart() (показано ниже):

export const getCart = () => {
    if (typeof window !== "undefined") {
        if (localStorage.getItem("cart")) {
            return JSON.parse(localStorage.getItem("cart"));
        }
    }
    return [];
};

Я намерен для getCart захватить тележку из localStorage и заполнить это в переменной состояния items или вернуть пустой массив [].
Насколько я понимаю, useEffect изменяет страницу всякий раз, когда изменяется состояние, и когда в массиве зависимостей есть какой-либо элемент, он будет основан на этом.
Ну, я не могу понять, почему это происходит ошибка.
Я действительно пытался понять эту ошибку can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render и вот что я узнал до сих пор, пытаясь решить эту проблему:

  1. items, зависимость не сильно меняется. Тестирование добавления 1 элемента или 0 элементов приводит к тысячам одинаковых ошибок
  2. Удаление useEffect полностью останавливает ошибку , но не позволяет привязать ее к элементам переменной состояния

Как я могу остановить эту ошибку?

Я просто хочу, чтобы этот компонент работал без зависания и выдачи тысяч ошибок при рендеринге.

Ответы [ 3 ]

1 голос
/ 04 августа 2020

Причина в ваших useEffect зависимостях:

useEffect(() => {
  setItems(getCart());
}, [items]);

Проблема в том, что вы передаете [items] и вызываете useEffect при изменении элементов. И внутри useEffect вы меняете items.

Убедитесь, что если вы возвращаете каждый раз новый объект или массив из getItems() response, вы не знаете, что ваши объекты такие же и снова вызывают эффект и снова.

Решение

Удалить элементы из зависимостей

useEffect(() => {
  setItems(getCart());
}, []);

Или, если вам нужно получить доступ к текущему состоянию при его изменении:

useEffect(() => {
  setItems(currentItems => getCart(currentItems));
}, []);
0 голосов
/ 04 августа 2020

Проблема здесь:

useEffect(() => {
        setItems(getCart());
    }, [items]);

Вы добавили зависимость с items. Это означает, что всякий раз, когда изменяется items, запускайте setItems(getCart());

. Но когда вы устанавливаете свои элементы, это означает, что элементы меняются, что, в свою очередь, снова запускает useEffect и, следовательно, бесконечное l oop.

Решение:

useEffect(() => {
            setItems(getCart());
        }, []);

Удалить зависимость. Это означает, что useEffect будет запущен, как только компонент будет mounted, и будет выполнен только один раз. Если вы хотите, чтобы это выполнялось по разным причинам, вам нужно будет добавить это в массив зависимостей.

0 голосов
/ 04 августа 2020

Вы должны вызвать setItems после возврата getCard Promiss или вы также можете использовать обратный вызов вместо promiss.

Сначала вам нужно получить результат, а после этого вызвать setItems. Это решит вашу проблему.

...