Ошибка: Слишком много повторных рендеров. React ограничивает количество рендеров, чтобы предотвратить бесконечный цикл. Как мне предотвратить эту ошибку?

#javascript #reactjs #react-native

Вопрос:

Это мой код. Я хочу добавить новую статью расходов в начало списка. Я надеялся получить некоторую помощь в том, как я могу создать новые расходы в верхней части списка. Я продолжаю получать одну и ту же ошибку: слишком много перерисовок. React ограничивает количество рендеров, чтобы предотвратить бесконечный цикл. Как я могу это исправить?

 import React, { useState } from "react";
import { Text, View, ScrollView } from "react-native";
import NewExpense from "../NewExpense";
import {
  selectTitle,
  selectPrice,
  selectCategory,
} from "../../slices/dataSlice";
import { useSelector } from "react-redux";

const RenderedExpense = () => {

  const title = useSelector(selectTitle);
  const price = useSelector(selectPrice);
  const category = useSelector(selectCategory);

  const enteredData = {
    id: Math.random().toString(),
    title: title.disTitle,
    price: price.disPrice,
    category: category.disCategory,
  };

  const expense = enteredData;

    const [expenseItems, setExpenseItems] = useState([]);
    setExpenseItems([expense, ...expenseItems]);


  return (
    <View>
      {
        (title.disTitle,
        price.disPrice,
        category.disCategory ? <NewExpense /> : null)
      }
      {
        expenseItems.map(() => {
          <NewExpense key={enteredData.id} /> })
      }
    </View>
  );
};
 

Комментарии:

1. Я думаю, что ваш бесконечный цикл начинается отсюда: const [expenseItems, setExpenseItems] = useState([]); setExpenseItems([расходы, …расходы]);

Ответ №1:

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

Если вы хотите установить состояние, как только компонент загрузится, вам следует использовать useEffect крючок.

Подобный этому:

 import React, { useState, useEffect } from "react";

...

const title = useSelector(selectTitle);
const price = useSelector(selectPrice);
const category = useSelector(selectCategory);

const enteredData = {
    id: Math.random().toString(),
    title: title.disTitle,
    price: price.disPrice,
    category: category.disCategory,
  };

const expense = enteredData;

const [expenseItems, setExpenseItems] = useState([]);

useEffect(()=>{
    setExpenseItems([expense, ...expenseItems]);
},[])
...
 

Обратите внимание, как я позвонил setExpenseItems внутрь useEffect . Он будет вызываться setExpenseItems только при первом отображении компонента. useEffect также принимает список зависимостей, который определит, будет ли выполняться то, что когда-либо указано в функции. Но я передал пустой массив в качестве своей зависимости.

Смотрите здесь для получения дополнительной информации.

Ответ №2:

Выполнение a setState запускает повторную визуализацию, поэтому у нас никогда не должно быть setState внутри метода визуализации, иначе произойдет цикл infitine.

Поскольку у вас есть setExpenseItems([expense, ...expenseItems]); внутренний метод визуализации, вы всегда будете получать это исключение.

Вы можете поместить эту деталь в эффект использования, который выполняется только при изменении значений в скобках, а не при каждом отображении компонента:

     useEffect(() => {
        const enteredData = {
            id: Math.random().toString(),
            title: title.disTitle,
            price: price.disPrice,
            category: category.disCategory,
        };

        const expense = enteredData;

        setExpenseItems([expense, ...expenseItems]);
    }, [title, price, category]);
 

Ответ №3:

Вы используете setExpenseItems([expense, ...expenseItems]); без каких-либо условий. При обновлении состояния компонент будет повторно отправлен, состояние будет обновлено снова, компонент повторно отправлен и так далее… бесконечная рекурсия. Вам нужно поведение, аналогичное componentDidMount() в дизайне класса React. Обычно для этого вы используете крючок эффекта: https://reactjs.org/docs/hooks-effect.html

В вашем Примере:

 useEffect(() => {
    setExpenseItems([expense, ...expenseItems]);
})