Тело вашей функции компонента запускается каждый раз, когда компонент визуализируется. Ваш компонент визуализируется каждый раз, когда React считает это необходимым, но обычно один раз при первоначальном добавлении на страницу, а затем снова при каждом изменении его состояния. (Несколько изменений состояния, выполняемых одновременно, обычно приводят только к одному рендеру, но если между ними есть разрыв, рендеринг будет выполняться после каждого.)
Код в useEffect
обратный вызов hook запускается после рендеринга в первый раз, а затем снова каждый раз, когда изменяется одна из перечисленных зависимостей. Поскольку в вашем коде нет списка зависимостей, обратный вызов перехватывается только один раз.
Вот простой пример:
const {useState, useEffect} = React;
const Example = () => {
const [counter, setCounter] = useState(0);
const [flag, setFlag] = useState(false);
// Runs after initial render, then again every time `flag` changes
useEffect(() => {
console.log(`useEffect #1 ran, flag = ${flag}`);
}, [flag]);
// Runs after initial render, then every time `flag` or
// `counter` changes
useEffect(() => {
console.log(`useEffect #2 ran, flag = ${flag}, counter = ${counter}`);
}, [flag, counter]);
// Runs after initial render only
useEffect(() => {
console.log(`useEffect #3 ran`);
}, []);
return (
<div>
<input type="button" value="Increment" onClick={() => setCounter(c => c + 1)} />
<input type="button" value="Flip Flag" onClick={() => setFlag(f => !f)} />
</div>
);
};
ReactDOM.render(<Example />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>
Вы можете найти эту статью Дана Абрамова полезной. В нем подробно рассказывается о том, как рендерит React, в контексте объяснения useEffect
(но это полезное чтение, даже отдельно от понимания useEffect
).