Реагирование состояния синхронизации реквизита вызывает ненужную первую повторную визуализацию - PullRequest
1 голос
/ 29 апреля 2020

Я хочу создать компонент Person, который полностью контролируется его состоянием. Он также должен иметь возможность синхронизировать c изменение реквизита (firstName, lastName), передаваемое из его родительского компонента в состояние. У меня есть следующий код. Он выполняет то, что мне нужно, а именно синхронизирует реквизиты с состоянием и выполняет повторную визуализацию после изменения состояния.

Однако я заметил одну проблему - useEffect вызывается после обновления DOM, вызванного изменением родительского реквизита. Таким образом, первоначальный повторный рендер теряется, так как я хочу, чтобы он повторялся только после того, как useEffect будет вызван и состояние будет изменено.

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

const Person = ({firstName, lastName}) =>  {
   const [name, setName] = useState(firstName + lastName)

   useEffect(() => {
       setName(firstName + lastName);
       console.log("state changed!");
   }, [firstName, lastName])

   console.log("re-render!");
   return <div>render {name}</div>;
}

export default Person;

Я создал простую демонстрацию здесь https://codesandbox.io/s/sparkling-feather-t8n7m , Если вы нажмете кнопку повторного рендеринга, в консоли вы увидите вывод ниже. Первый re-render! вызван изменением реквизита, которого я хочу избежать. Есть идеи как этого добиться? Я знаю, что есть и другие решения, такие как полный контроль над ним, но я хотел бы знать, есть ли обходной путь для этого решения

re-render!
state changed!
re-render!

Ответы [ 2 ]

1 голос
/ 29 апреля 2020

вам нужно будет добавить условие в ваш useEffect. что-то вроде:

const [didUpdate, setDidUpdate] = useState(false);

useEffect(() => {
  if(didUpdate){
    setName(firstName + lastName);
    console.log('state changed!');
  } else {
    setDidUpdate(true);
  }
}, [firstName, lastName]);

Здесь он воспроизводит поведение componentDidUpdate ().

При первом рендеринге компонент монтируется, didUpdate инициализируется как false, поэтому для эффекта будет установлено только значение Значение true для следующих обновлений.

Обратите внимание, что состояние (useState), инициализированное реквизитом, не обновляется при изменении реквизита.

0 голосов
/ 29 апреля 2020

Это в основном поведение ядра React, согласно do c

Функция, переданная в useEffect, запустится после фиксации рендера на экране.

, чтобы избежать ошибок, вызванных побочными эффектами.

Полагаю, вы немного упростили свой пример, но вы должны знать, что копирование реквизитов в безусловное состояние является анти-паттерном https://en.reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#anti -pattern-безусловно-copying-props-to-state

Вместо этого вы должны напрямую использовать реквизиты:

const Person = ({firstName, lastName}) => (
  <div>render {firstName + lastName}</div>;
);
...