Я проводил некоторые тесты со следующим фиктивным компонентом, где после выполнения (в консоли) я получаю следующий результат:
Rendering: 0
Triggered: 0
Rendering: 4
Triggered: 4
Rendering: 4
Я изо всех сил пытаюсь понять, почему.
Первый рендеринг:
- устанавливает
index
в0
. - запускает useEffect, поскольку
undefined
не является0
- useEffect запрашивает настройку
index
на4
Второй рендер:
index
равно4
- почему тело useEffect выполняется снова?
Третий рендер:
- почему есть повторный рендеринг?
То, что я ожидал бы это:
Rendering: 0
Triggered: 0
Rendering: 4
Я пропускаю что-то очень очевидное? Не могли бы вы помочь мне понять, как это работает под капотом?
const Example = React.memo(() => {
const [index, setIndex] = React.useState(0)
console.log('Rendering: ', index)
React.useEffect(() => {
console.log('Triggered: ', index)
setIndex(4)
}, [index])
return <h1>{index}</h1>
})
ReactDOM.render(<Example />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
3 ответа
Количество повторных рендеров на самом деле верное. Давайте проанализируем, что происходит:
- Визуализация 0 — это первая визуализация при монтировании (в этом состоянии каждый
useEffect
запускается автоматически)
- Инициировано 0 — это начальное срабатывание
useEffect
.
- Визуализация 4 – эта повторная визуализация вызвана тем, что вы установили для нового состояния
index
значение4
- Триггер 4 – это вызвано тем, что вы изменили
index
с 0 на 4.
- Визуализация 4 – это выполняется, поскольку состояние изменяется с
4
на4
(даже если значение остается тем же, оно вызовет повторную визуализацию компонента, поскольку React не знает, установили ли вы то же состояние, и его нужно запустить снова). В этом повторном рендеринге useEffect не запускается, посколькуindex
снова равно 4.
Обоснование
Если что-либо изменится в компоненте в какой-либо момент, например useState
useContext
, customHook
, этот компонент необходимо будет перерисовать. Это также происходит, если родительский компонент перерисовывается, дочерний компонент будет перерисовываться, даже если в вашем компоненте не было никаких изменений.
Дополнительные советы и информация по ререндерингу
Чтобы предотвратить ненужный повторный рендеринг родительских компонентов дочерних компонентов, вы можете использовать React.memo. , это приведет к повторному рендерингу вашего компонента, если реквизиты изменятся, но не предотвратит повторный рендеринг вашего компонента, если там изменится состояние или какой-либо из вышеперечисленных хуков.
Если это кажется излишним, то звучит так, но это необходимо, чтобы реакция была уверена, что имеет самое последнее состояние. Такой запуск JS быстрее, чем наличие некоторой памяти состояния, которая проверяет изменения, а также более прозрачен для разработчика (и как VDOM создается)
Ожидаемый результат не может быть достигнут.
UseEffect отображается при монтировании компонента и при каждом повторном рендеринге при изменении состояния (индекс).
const Example = () => {
const [index, setIndex] = React.useState(0)
console.log('Rendering: ', index)
React.useEffect(() => {
console.log('Triggered: ', index)
setIndex(4)
}, [index])
return <h1>{index}</h1>
}
Выход:
- Визуализация: 0 => Когда компонент монтируется в первый раз, этот временной индекс равен 0
- Triggered: 0 => При монтировании срабатывает useEffect и состояние обновляется (от 0 до 4)
- Визуализация: 4 => Компонент повторно визуализируется, так как состояние изменилось с (0 на 4)
- Triggered: 4 => useEffect срабатывает повторно, так как состояние изменилось (от 0 до 4)
- Визуализация: 4 => Компонент повторно визуализировался, чтобы проверить, изменилось ли состояние или нет (от 4 до 4, вид подтверждения, что ничего не изменилось)
Способ работы useEffect заключается в том, что он запускается только после рендеринга компонента страницы.
Надеюсь, это поможет вам понять.
1-й индекс рендеринга равен 0.
Rendering: 0
Он запускает useEffect.
Triggered: 0
Индекс обновляется в useEffect, но не в компоненте. Затем рендер обновляет индекс до 4.
Rendering: 4
UseEffect запускается, потому что индекс изменился.
Triggered: 4
Компонент визуализируется снова, но индекс по-прежнему равен 4, поэтому useEffect больше не запускается.
Rendering: 4
Похожие вопросы
Новые вопросы
javascript
По вопросам программирования на ECMAScript (JavaScript / JS) и его различных диалектах / реализациях (кроме ActionScript). Включите все соответствующие теги в свой вопрос; например, [node.js], [jquery], [json] и т. д.
index
; по умолчанию useEffect выполняется после начального рендеринга. "почему тело useEffect выполняется снова?" — потому что useEffect зависит отindex
, и вы изменили состояние внутри useEffect, установивindex
на 4.