Знайте разницу между передаваемым значением и передаваемой функцией.
Давайте сразу перейдем к сути и зададим два вопроса: почему у нас есть возможность передать функцию в setState и как передача функции решает эту проблему?
setState является асинхронным
Если вы еще не знаете, setState () на самом деле является асинхронным, чтобы React мог объединить несколько вызовов setState () в один повторный рендеринг для повышения производительности. Представьте, что вам нужно повторно визуализировать каждый раз, когда только один компонент вызывает setState (). Это будет невероятно медленно!
Это также причина, по которой у нас еще нет доступа к новому состоянию, когда мы пытаемся сослаться на него сразу после вызова setState ().
const [ count, setCount ] = useState(3) const onClick = () => { setCount(5) console.log(count) // first click will print out 3 } return(<button onClick={onClick}> hello </button>)
Проблема
Но что, если следующее состояние зависит от текущего состояния. Давайте представим простой счетчик, который можно увеличивать нажатием кнопки:
const [ count, setCount ] = useState(0) const onClick = () => { setCount(count + 1) } return( <div> <span> { count } </span> <button onClick={onClick}> increment! </button> </div> )
Каждый раз, когда мы щелкаем по кнопке, мы будем увеличивать счетчик с помощью setCount (), который затем будет сигнализировать React о повторном рендеринге этого компонента.
А что, если у пользователя открыто много вкладок и приложений или они могут щелкать так быстро, что React объединяет наши вызовы setCount (), дело в том, что состояние не обновляется, пока пакет не будет завершен.
Итак, если мы представим пакетную обработку двух вызовов setCount (), это будет примерно так:
// let's say count is 5 setCount(count + 1) // count is 5, becomes 6 setCount(count + 1) // count is still 5, becomes 6 // re-renders, count becomes 6
мы могли видеть, что даже несмотря на то, что мы вызвали setCount () для увеличения нашего счетчика в два раза, он увеличился только один раз, потому что они были объединены вместе, и это второе приращение теряется.
Решение
Таким образом, появляются функции, которые спасают положение. Давайте возьмем предыдущий сценарий выше, но вместо этого передадим функцию.
// let's say count is 5 setCount(current => current + 1) // current is 5, becomes 6 setCount(current => current + 1) // current is 6, becomes 7 // re-renders, count becomes 7
И вот, передача функции позволяет нам правильно увеличивать наше состояние, даже когда React выполняет пакетную обработку наших вызовов setState ().
Счетчик - это очень простой пример, но попробуйте подумать о больших приложениях, которые имеют несколько состояний в разных компонентах. React должен выполнять пакетные вызовы setState (), чтобы наше приложение оставалось плавным и реактивным.
Больше глубины
Проблема заключается в том, что закрытие и React не обновляют наше состояние мгновенно, пока пакет не будет завершен. Потому что, если мы передадим значение в React, он не узнает, как это значение рассчитывается, а будет знать только результат. Итак, давайте снова рассмотрим предыдущий сценарий, в котором мы передаем значение:
// let's say count is 5 setCount(count + 1) --> setCount(6) setCount(count + 1) --> setCount(6) // re-renders, count becomes 6
Итак, что мы говорим React, это просто установить наш счетчик на 6. Теперь давайте посмотрим, как это будет выглядеть, когда вместо этого мы передадим функцию.
// let's say count is 5 setCount(current => current + 1) --> setCount(5 => 5 + 1) setCount(current => current + 1) --> setCount(6 => 6 + 1) // re-renders, count becomes 7