Бесконечный цикл рендеринга при использовании информации из ссылок для установки состояния - PullRequest
1 голос
/ 11 апреля 2019

У меня есть родительские функциональные компоненты, которые используют хук useState для установки состояния (тот факт, что эта проблема связана с хуками, не имеет значения, потому что я испытывал то же поведение при использовании компонента класса), и ему нужно установить состояние для некоторой информации, которая он собирается при рендеринге потомков, но когда состояние установлено, он снова перерисовывает потомков, вызывая бесконечный цикл

export const SomeConst = (props) => {

  const [information, setInformation] = useState([]);
  const newInfo = []

    const reportBoundingRectWithIndex = (index) => {
      return (width, left) => {
        newInfo[index] = { width, left };
        setInformation(newInfo);
      };
    };

  return (
    {children.map(child => (
        <ChildComponent
            reportBoundingRect={reportBoundingRectWithIndex(index)}
            />
        ))}
    )}

Представленные дочерние компоненты имеют это в useEffect (optionElement создается с использованием useRef):

useEffect(() => {
const elementInfo = optionElement.current.getBoundingClientRect();
props.reportBoundingRect(elementInfo.width, elementInfo.left); });

Это только упрощенная версия кода, я добавил этот const newInfo для сбора этого нового массива информации, без него ширина и левая информация теряются из памяти, потому что setState асинхронный и ждет дополнительных изменений (но когда он действительно вызывается, этой информации больше нет и он становится неопределенным в этом массиве)

Я пробовал это в компонентах с состоянием, но результат с componentDidMount и setState и все то же самое, я действительно хотел бы получить некоторый указатель о том, как должен быть достигнут упомянутый behvaiour

Любая помощь очень ценится

1 Ответ

0 голосов
/ 11 апреля 2019

Таким образом, проблема в вашем коде состоит в том, что ваш useEffect в дочернем элементе не должен вызываться при каждом обновлении, иначе это приведет к бесконечному циклу, так как в useEffect вы вызываете родительскую функцию, которая обновляет состояние и вызывает-рендер, который снова запускает useEffect

export const SomeConst = (props) => {

  const [information, setInformation] = useState([]);
  const newInfo = []

    const reportBoundingRectWithIndex = (index) => {
      return (width, left) => {
        newInfo[index] = { width, left };
        setInformation(newInfo);
      };
    };

  return (
    {children.map(child => (
        <ChildComponent
            reportBoundingRect={reportBoundingRectWithIndex(index)}
            />
        ))}
    )}
  )
}

и в дочернем вызове useEffect только при начальном рендеринге (или некоторых изменениях)

useEffect(() => {
   const elementInfo = optionElement.current.getBoundingClientRect();
   props.reportBoundingRect(elementInfo.width, elementInfo.left);
}, []);
...