Содержание статьи
Эта статья рассчитана на людей, уже имеющих первый подход к React, и которые, как новички, сомневаются в том, как setState
работает и как им правильно воспользоваться. Это также должно помочь разработчикам среднего и старшего уровня использовать более чистые и абстрактные способы установления состояния, а также заставить функции высшего порядка обрабатывать и абстрактное состояние.
Просто читайте и получайте удовольствие!
Бери чашку кофе и продолжай читать! ?
Основные понятия setState()
Компоненты React позволяют разделить пользовательский интерфейс (UI) на независимые части, которые можно использовать повторно, чтобы вы могли думать о каждой части в отдельности.
Концептуально компоненты похожи на функции JavaScript. Они принимают произвольные вводы (так называемые реквизиты) и возвращают элементы React, описывающие то, что должно появиться на экране.
Если вам нужно дать пользователю возможность что-нибудь ввести или каким-то образом изменить переменные, которые компонент получает как реквизит, вам понадобится setState
.
Независимо от того, объявляете ли вы компонент как функцию или класс, он никогда не должен изменять свои собственные свойства.
Все компоненты React должны действовать как чистые функции в отношении своих реквизитов. Это означает функции, которые никогда не пытаются изменить свои входные данные и всегда возвращают тот же результат для тех же входов.
Конечно, интерфейс программы динамичен и изменяется со временем. Вот поэтому state
было создано.
State
позволяет компонентам React изменять свой выход со временем в ответ на действия пользователя, ответы сети и все остальное, не нарушая это правило.
Компоненты, определенные классами, имеют некоторые дополнительные возможности. Локальное состояние является функцией, доступной только классу Components.
setState
– это метод API, предоставляемый в библиотеке, чтобы пользователь мог определить состояние и манипулировать им со временем.
Три правила большого пальца при использовании setState()
Не меняйте состояние напрямую

Обновления состояния могут быть асинхронными
React может создавать несколько пакетов setState()
вызывает в единое обновление для производительности.
Поскольку this.props
и this.state
могут обновляться асинхронно, не следует полагаться на их значения для вычисления следующего состояния.

Вы всегда должны выполнять подобные манипуляции с функциональным подходом, обеспечивая state
и props
и возвращение нового state
на основе прежнего.
Обновления состояния объединены
Когда ты звонишь setState()
React объединяет предоставленный вами объект с текущим state
.
В следующем примере мы обновляем переменную dogNeedsVaccination
независимо от другого state
переменные.
Слияние неглубоко, следовательно this.setState({ dogNeedsVaccination: true })
оставляет другие переменные неприкосновенными, заменяя только значение dogNeedsVaccination
.

Уважайте поток данных и не указывайте макс.
Данные стекают вниз! Ни родительские, ни дочерние компоненты не могут знать, есть ли определенный компонент с сохранением состояния или без состояния, и им не должно быть безразлично, как оно определено как функция или класс.
Вот поэтому state
часто называют местным или инкапсулированным. Он не доступен ни для одного компонента, кроме того, который владеет и устанавливает его.
Когда ты setState
prop и используйте его в своем компоненте, вы нарушаете поток реквизитов визуализации. Если по какой-либо причине параметр, переданный в ваш компонент, изменился в родительском компоненте, ребенок не будет повторно воспроизводиться автоматически?!
Давайте проверим пример:

Вот у вас есть Home
Компонент, генерирующий магическое число каждые 1000 мс и устанавливающий его собственным state
.
После этого он отображает число и вызывает три Child
Компоненты (Братья и сестры), которые получат магическое число с целью отображения его с помощью трех разных подходов:
Первый подход
Компонент ChildOfHome
уважает каскадный поток реквизитов React и, учитывая, что целью является лишь показать магическое число, он отображает props
получено напрямую.

Второй подход
Компонент ChildOfHomeBrother
получает props
от своего отца и, вызывая componentDidMount
устанавливает магическое число в state
. Затем он предоставляет state.magicNumber
.
Этот пример не работает, потому что render()
не знает, что а prop
изменился, поэтому он не запускает повторное воспроизведение компонента. Поскольку компонент больше не воспроизводится повторно, componentDidMount
не вызывается и дисплей не обновляется.

Третий подход
Обычно, когда мы пытаемся заставить это работать с помощью второго подхода, мы думаем, что чего-то не хватает. Вместо того чтобы сделать шаг назад, мы продолжаем добавлять вещи в код, чтобы он работал!
Поэтому в этом третьем подходе мы добавили componentDidUpdate
чтобы проверить, есть ли изменения props
для запуска повторного воспроизведения компонента. Это не нужно и ведет нас к нечистому коду. Это также несет с собой затраты на производительность, которые будут умножены на количество раз, когда мы делаем это в большом приложении, где у нас много связанных компонентов и побочных эффектов.
Это неправильно, если вам не нужно разрешить пользователю изменить полученное значение prop.
Если вам не нужно изменять значение prop, всегда старайтесь поддерживать работу в соответствии с потоком React (Первый подход).
Вы можете проверить рабочую веб-страницу по этому примеру, который я подготовил для вас в Glitch. Посмотрите и повеселитесь?
Также проверьте код в Home.js
и HomeCodeCleaned.js
(без материалов HTML) в моем репо об этой статье.
Как установитьState
Поэтому я думаю, что пора испачкать руки!
Давайте немного поиграем setState
и улучшайте это! Просто следуйте и возьмите еще одну чашку кофе!
Давайте создадим небольшую форму для обновления данных пользователя:

Вот код для примера выше:

Мы устанавливаем state
как объект, и нет никаких проблем, потому что наше текущее состояние не зависит от нашего последнего состояния.
Что делать, если мы создадим еще одно поле формы для ввода и отображения фамилии?


Хорошо! Мы абстрагировали handleFormChange
метод, чтобы иметь возможность обрабатывать все поля ввода и setState
.
Что делать, если мы добавим переключатель, чтобы пометить данные как действительные или недействительные, и счетчик, чтобы знать, сколько изменений мы внесли в состояние?


Да! Мы качаемся! Мы многое абстрагировали!
Хм… Скажем, я не хочу, чтобы флажок управлял isValid
сменная, но простая кнопка переключения.
Давайте отделим обработчик счетчика от этого метода. Это хорошо работает, но в более сложных ситуациях, когда React нуждается в пакетных/групповых изменениях, не стоит полагаться на this.state.counter
переменную, чтобы добавить еще одну. Это значение может изменяться без вашего ведома.
Мы используем его небольшую копию в момент вызова операции, и в этот определенный момент времени вы не знаете, есть ли ее значение тем, что вы ожидали или нет!
Давайте немного функциональны!


Ладно — мы потеряли абстракцию, потому что отделили обработчики, но на это весомая причина!
Поэтому в это время мы сохраняем handleFormChange
передача объекта в setState
Метод API. Но handleCounter
и handleIsValid
Теперь методы функционируют и начинают с захвата текущего состояния, а затем в зависимости от этого состояния изменения его на следующее.
Это правильный способ изменения state
переменных, зависящих от предыдущего состояния.
А если мы хотим console.log()
изменения состояния firstName
и lastName
формы ввода каждый раз, когда происходит изменение? Давайте попробуем!

Хорошо! Каждый раз handleFormChange
происходит (что означает, что произошло новое нажатие клавиши). logFields()
метод вызывается и регистрирует текущее состояние в консоли!
Давайте проверим консоль браузера:

Подождите! Что здесь произошло, люди? Журнал консоли – это одно изменение перед вводом текущей формы! Почему это происходит?
setState является асинхронным!!
Мы уже знали это, но теперь мы видим нашими глазами! Что там происходит? Давайте посмотрим на handleFormChange
и logFields
методы выше.
Итак, handleFormChange
метод получает имя и значение события, а затем выполняет setState
этих данных. Затем он вызывает handleCounter
чтобы обновить информацию счетчика, и в конце вызывает logFields
метод. The logFields
метод захватывает currentState
и возвращает Эдуард вместо Эдуардо.
Дело в том: setState
является асинхронным и бездействует в данный момент. React выполняет свою работу и выполняет logFields
метод сначала, оставляя setState
для последующего цикла событий.
Но как мы можем избежать такой ситуации?
Ну, setState
API имеет a callback
чтобы избежать этой ситуации:

Если мы хотим logFields()
чтобы учесть последние изменения, которые мы внесли в состояние, нам нужно вызвать его внутри обратного вызова, например:

Ладно, теперь это работает!
Мы говорим React: «Эй, React! Следите за этим, когда вы вызываете logFields
метод Я хочу, чтобы вы имели state
уже обновлено, хорошо? Я доверяю тебе!»
React говорит: «Хорошо, Эдо! Я собираюсь справиться со всеми этой партией вещей, которые я обычно делаю на заднем дворе вместе с setState
вещь, и только когда я закончу с этим, я призываю logFields()
! Крутой чувак! Расслабься!»

И собственно сработало!
Хорошо всем! К этому времени мы справились с основными подводными камнями setState
.
Хватит ли вам смелости выйти за стену? Возьмите чашечку кофе, и давайте по-настоящему гулять…
Станьте модным из setState()
Теперь, когда мы имеем handleCounter
и handleIsValid
методы и setState()
Выраженные функциями, мы можем составить обновление состояния с другими функциями! Мне нравится композиция! Давай развлечемся!

Мы можем принять логику внутрь setState
к функции вне компонента класса. Назовем это toggleIsValid
. ☝️

Теперь эта функция может существовать вне компонента класса в любом месте вашего приложения.
Что делать, если мы используем функцию высшего порядка?

Вот Да! Теперь мы не призываем toggleIsValid
больше функционировать. Мы вызываем абстрактную функцию высшего порядка, которая называется toggleKey
и передача в него ключа (в данном случае строчки).
Как нам нужно изменить toggleIsValid
функционировать сейчас?

Что? Теперь у нас есть функция под названием toggleKey
что получает a key
и возвращает новую функцию, изменяющую состояние в соответствии с предоставленным ключом.
Это toggleKey
может быть в библиотеке или вспомогательном файле. Его можно вызвать во многих разных контекстах, чтобы изменить состояние того, что вы хотите, на его противоположность.
Прекрасно!
Сделаем то же самое с обработчиком счетчика прироста:


Да! Это работает! Да мило. Давайте сейчас сходят с ума…
Съемка на Луну и возвращение
Что делать, если мы создадим генерик makeUpdater
функция, получающая функцию преобразования, которую вы хотите применить, принимает ключ и возвращает функцию состояния, которая управляет состоянием с помощью функции преобразования и ключа? Немного запутались? Пойдем!

Ладно, хватит… Давайте остановимся здесь. ?
Вы можете проверить весь код, сделанный в этом репозитории GitHub.
Последнее, но не последнее
Не забывайте избегать максимального использования состояния и уважайте каскад рендеров React.
Не забывайте setState
является асинхронным.
Не забывайте setState
может принимать объект или функцию
Не забывайте, что вы должны передать функцию, когда ваше следующее состояние зависит от вашего предыдущего состояния.
Библиография
- Документация React
- Reach Tech Courses Райана Флоренса, которые я очень рекомендую.
Спасибо большое!