#javascript #reactjs #rendering
Вопрос:
Я написал простой React, чтобы проверить, как React рендерится
import ReactDOM from 'react-dom';
import React, { useState, useEffect } from 'react';
const App = (props) => {
// State
const [trackIndex, setTrackIndex] = useState(1);
const [trackProgress, setTrackProgress] = useState(0);
const clickHandler = () =>{
setTrackIndex((trackIndex)=>trackIndex 1)
}
useEffect(() => {
console.log("effect; trackIndex=",trackIndex)
console.log("effect; trackProgress=",trackProgress)
if(trackIndex<5){
console.log("set trackProgress")
setTrackProgress(trackIndex)
}
});
console.log("render")
return (
<div>
<p>{trackIndex}</p>
<p>{trackProgress}</p>
<button onClick={clickHandler}>Click me</button>
</div>
);
};
ReactDOM.render(
<App />,
document.getElementById('root')
);
Ниже приведен вывод консоли:
render
effect; trackIndex= 1
effect; trackProgress= 0
set trackProgress
render
effect; trackIndex= 1
effect; trackProgress= 1
set trackProgress
render
Кажется, что React отображается три раза, прежде чем я нажму кнопку. Последний рендеринг меня действительно смущает. Может ли кто-нибудь объяснить мне, почему происходит этот рендеринг и почему после этого рендеринга не выполняется никакого эффекта? Заранее благодарю
Ответ №1:
Кажется, что вы useEffect
устанавливаете состояние с помощью параметра setTrackProgress
on при первоначальном рендеринге компонента. Это потому trackIndex
, что начинается с 1
того, что меньше 5. (видно по if(trackIndex<5)
) Обратите внимание, что вы не указали зависимость от массива в useEffect
качестве второго параметра. Согласно react-documentation это означает, что эффект будет возникать только один раз после первого начального рендеринга компонента.
Кроме того, я бы предложил добавить useCallback
к вашему clickHandler
, чтобы предотвратить переопределение функции для каждого рендеринга. (Согласно react-documentation)
Ответ №2:
Вы практически создаете бесконечный цикл, но React спасает вас. Первый render
журнал — это начальный рендеринг, затем useEffect
выполняется, и ваш компонент повторно отображает, что приводит ко 2-му render
журналу и первому effect; ...
журналу. Теперь useEffect
выполняется 2-й. Однако значение trackIndex
не изменилось, поэтому ваш оператор if будет оценивать true и обновляться trackProgress
с тем же состоянием / значением (1). Это приводит к еще одному повторному отображению и третьему render
журналу. Теперь вы могли бы подумать, что useEffect
будет выполнен 3-й, но React достаточно умен, чтобы знать, когда состояние не изменилось, и, следовательно, не выполняет useEffect
.
Добавьте зависимости к вашему useEffect
, как указано выше. Это решит вашу проблему.
useEffect(
...
, [trackIndex])