#reactjs
#reactjs
Вопрос:
Я испытывал какое-то странное поведение в своем приложении React, где setEffect с состоянием (скажем, state1) в качестве второго аргумента изменял другую переменную (не состояние) без вызова setState1 . Итак, я создал следующий код, чтобы посмотреть, произойдет ли то же самое, и это произошло:
import React, { useState, useEffect } from 'react';
function App() {
let [state1, setState1] = useState('');
let count = 0;
useEffect(() => {
count = count 1000;
console.log('USEEFFECT_count: ' count);
}, [state1]);
setInterval(() => {
console.log('SETINTERVAL_count: ' count);
}, 1000);
return (
<div className="App">
</div>
);
}
export default App;
По сути, переменная count должна получать значение 1000 только при вызове setState1 (чего никогда не происходит) для изменения значения state1 . Но возврат консоли
SETINTERVAL_count: 1000
SETINTERVAL_count: 0
SETINTERVAL_count: 1000
SETINTERVAL_count: 0
SETINTERVAL_count: 1000
SETINTERVAL_count: 0
SETINTERVAL_count: 1000
SETINTERVAL_count: 0
SETINTERVAL_count: 1000
SETINTERVAL_count: 0
И консоль.журнал внутри useEffect никогда не вызывается, как и ожидалось. Но если это так, то:
- почему он суммирует 1000 для подсчета?
- почему это значение сбрасывается на 0?
Если я добавлю state2 и другой useEffect, который суммирует 5000 для подсчета, он добавляет к 1000 от первого useEffect :
import React, { useState, useEffect } from 'react';
function App() {
let [state1, setState1] = useState('');
let [state2, setState2] = useState('');
let count = 0;
useEffect(() => {
count = count 1000;
console.log('USEEFFECT1_count: ' count);
}, [state1]);
useEffect(() => {
count = count 5000;
console.log('USEEFFECT2_count: ' count);
}, [state2]);
setInterval(() => {
console.log('SETINTERVAL_count: ' count);
}, 1000);
return (
<div className="App">
</div>
);
}
export default App;
Результат console.log:
SETINTERVAL_count: 6000
SETINTERVAL_count: 0
SETINTERVAL_count: 6000
SETINTERVAL_count: 0
SETINTERVAL_count: 6000
SETINTERVAL_count: 0
SETINTERVAL_count: 6000
SETINTERVAL_count: 0
Ответ №1:
В выводе, который вы получаете с помощью своего кода, нет ничего странного.
В вашем коде useEffect
hook будет выполняться только один раз, т. Е. После первоначального рендеринга. Тогда он будет выполняться только в том случае, если state1
изменен, но этого никогда не происходит в вашем коде, поэтому useEffect
выполняется только один раз и устанавливается count
в 1000
значение .
И консоль.журнал внутри useEffect никогда не вызывается, как и ожидалось
Нет, он будет вызван. useEffect
будет выполняться после первоначального рендеринга, поэтому count
значение s становится 1000
. Наличие state1
в массиве зависимостей useEffect
hook не означает, что он будет выполняться только при state1
изменении. useEffect
всегда выполняется после первоначального рендеринга, независимо от того, передаете ли вы массив зависимостей или нет, или если вы передаете непустой массив зависимостей.
Теперь вопрос о том, почему setInterval
регистрируются два значения count
?
Это потому, что в вашем коде установлены два интервала. Один раз во время начального рендеринга, когда count
есть 0
, и второй из Strict Mode
-за того, что он дважды отображает ваш компонент.
Как setInterval()
вызывается на верхнем уровне из вашего компонента, новый интервал будет устанавливаться всякий раз, когда компонент повторно отображает. Поскольку ваш компонент отображается два раза, устанавливаются два интервала. Функция обратного вызова каждого интервала имеет замыкание по count
сравнению с функцией обратного вызова, когда она определена.
В index.js
файле вы увидите App
компонент, завернутый, React.StrictMode
как показано ниже:
<React.StrictMode>
<App/>
</React.StrictMode>
Если вы удалите React.StrictMode
компонент, вы увидите, что count
на консоль будет записано только одно значение
Вывод без строгого режима:
USEEFFECT_count: 1000
SETINTERVAL_count: 1000
SETINTERVAL_count: 1000
SETINTERVAL_count: 1000
SETINTERVAL_count: 1000
Ответ №2:
Ваш вызов setInterval
находится в теле компонента, поэтому это будет происходить каждый раз, когда компонент выполняет рендеринг. Ваш компонент выполняет рендеринг дважды, поэтому он устанавливает два интервала. Каждый интервал ссылается на другую count
переменную. Один из count
s равен 1000, потому useEffect
что соответствующий этому рендеринг выполнен. Другое значение равно 0, потому что оно useEffect
не запущено (поскольку состояние 1 не изменилось).
Причина, по которой есть два рендеринга, вероятно, в том, что вы используете строгий режим react, который намеренно выполняет двойные рендеринги. Это сделано, чтобы помочь выявить ошибки, из-за которых ваш код зависит от количества рендеринга компонента. Похоже, он выполняет свою работу, поскольку подчеркивает вашу зависимость от количества рендеров.