react что такое state

React: основные подходы к управлению состоянием

react что такое state. Смотреть фото react что такое state. Смотреть картинку react что такое state. Картинка про react что такое state. Фото react что такое state

Доброго времени суток, друзья!

Предлагаю вашему вниманию простое приложение — список задач. Что в нем особенного, спросите вы. Дело в том, что я попытался реализовать одну и ту же «тудушку» с использованием четырех разных подходов к управлению состоянием в React-приложениях: useState, useContext + useReducer, Redux Toolkit и Recoil.

Начнем с того, что такое состояние приложения, и почему так важен выбор правильного инструмента для работы с ним.

Состояние — это собирательное понятие для любой информации, имеющей отношение к приложению. Это могут быть как данные, используемые в приложении, такие как тот же список задач или список пользователей, так и состояние как таковое, например, состояние загрузки или состояние формы.

Условно, состояние можно разделить на локальное и глобальное. Под локальным состоянием, обычно, понимается состояние отдельно взятого компонента, например, состояние формы, как правило, является локальным состоянием соответствующего компонента. В свою очередь, глобальное состояние правильнее именовать распределенным или совместно используемым, подразумевая под этим то, что такое состояние используется более чем одним компонентом. Условность рассматриваемой градации выражается в том, что локальное состояние вполне может использоваться несколькими компонентами (например, состояние, определенное с помощью useState(), может в виде пропов передаваться дочерним компонентам), а глобальное состояние не обязательно используется всеми компонентами приложения (например, в Redux, где имеется одно хранилище для состояния всего приложения, обычно, создается отдельный срез (slice) состояния для каждой части UI, точнее, для логики управления этой частью).

Важность выбора правильного инструмента для управления состоянием приложения обусловлена теми проблемами, которые возникают при несоответствии инструмента размерам приложения или сложности реализуемой в нем логики. Мы убедимся в этом в процессе разработки списка задач.

Я не буду вдаваться в подробности работы каждого инструмента, а ограничусь общим описанием и ссылками на соответствующие материалы. Для прототипирования UI будет использоваться react-bootstrap.

Создаем проект с помощью Create React App:

useState()

Хук «useState()» предназначен для управления локальным состоянием компонента. Он возвращает массив с двумя элементами: текущим значением состояния и сеттером — функцией для обновления этого значения. Сигнатура данного хука:

Пока ограничимся четырьмя базовыми операциями: добавление, переключение (выполнение), обновление и удаление задачи, но усложним себе жизнь тем, что наше начальное состояние будет иметь форму нормализованных данных (это позволит как следует попрактиковаться в иммутабельном обновлении).

Думаю, тут все понятно.

В App.js мы с помощью useState() определяем начальное состояние приложения, импортируем и рендерим компоненты приложения, передавая им состояние и сеттер в виде пропов:

В TodoForm.js мы реализуем добавление новой задачи в список:

В TodoList.js мы просто рендерим список элементов:

Наконец, в TodoListItem.js происходит самое интересное — здесь мы реализуем оставшиеся операции: переключение, обновление и удаление задачи:

Заключение

Итак, мы с вами реализовали список задач с использованием четырех разных подходов к управлению состоянием. Какие выводы можно из всего этого сделать?

Я выскажу свое мнение, оно не претендует на статус истины в последней инстанции. Разумеется, выбор правильного инструмента для управления состоянием зависит от задач, решаемых приложением:

Источник

Рассмотрим пример работы часов. Мы привязываем ReactDOM.render()изменить отображаемый вывод:

В этом пример будет описано, как сделать Clock компонент действительно повторно используемым и инкапсулированным. Он будет настраивать свой собственный таймер и обновлять каждую секунду.

Мы можем начать с инкапсуляции того, как выглядят часы:

Тем не менее, это не соответствует критическому требованию: тот факт, что Clock настройка таймера и обновление пользовательского интерфейса каждую секунду должна быть деталью реализации Clock.

В идеале мы хотим написать это один раз и иметь Clock само-обновляемым:

Чтобы реализовать это, нам нужно добавить «состояние» (state) к Clock компоненту. Состояние похоже на реквизит, но оно является частным и полностью контролируется компонентом.

Преобразование функции в класс

Вы можете преобразовать функциональный компонент как Clock класс в пять шагов:

Clock теперь определяется как класс, а не функция. Это позволяет нам использовать дополнительные функции, такие как локальные состояния и перехваты жизненного цикла.

Добавление локального состояния в класс

Мы переместим его date из реквизита в три этапа:

1) Замените с this.props.date на this.state.date в render() методе:

2) Добавьте конструктор класса, который назначает начальную this.state:

Обратите внимание, как мы переходим props к базовому конструктору:

Компоненты класса всегда должны ссылаться на базовый конструктор props.

3) Снимите date с элемента:

Позднее мы добавим код таймера обратно к самому компоненту. Результат выглядит следующим образом:

Затем мы сделаем Clock настройку собственного таймера и обновим каждую секунду.

Добавление методов жизненного цикла в класс

В приложениях со многими компонентами очень важно высвобождать ресурсы, используемые компонентами при их уничтожении. Мы хотим настроить таймер всякий раз, когда Clock отображается в DOM в первый раз. Это называется «установка» (mounting) в React. Мы также хотим очистить этот таймер всякий раз, когда DOM, созданный Clock удаляется. Это называется «размонтирование» (unmounting) в React. Мы можем объявить специальные методы для класса компонентов для запуска некоторого кода, когда компонент монтирует и размонтирует:

Эти методы называются «крючки жизненного цикла». На componentDidMount() крючок работает после компонентного выхода было оказано DOM. Это хорошее место для установки таймера:

Обратите внимание, как мы сохраняем идентификатор таймера this. Хотя this.props настроен самим Реактом и this.state имеет особое значение, вы можете добавлять дополнительные поля в класс вручную, если вам нужно сохранить что-то, что не участвует в потоке данных (например, идентификатор таймера).

Мы разрушим таймер в componentWillUnmount() крючке жизненного цикла:

Правильное использование setState()

Есть три вещи, которые вы должны знать о setState():

Не изменять состояние напрямую

Например, это не приведет к повторному рендерингу компонента:

Вместо этого используйте setState():

Единственным местом, где вы можете назначить, this.state является конструктор.

Обновления состояния могут быть асинхронными

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

Например, этот код может не обновить счетчик:

Чтобы исправить это, используйте вторую форму, setState() которая принимает функцию, а не объект. Эта функция получит предыдущее состояние в качестве первого аргумента и реквизит во время обновления в качестве второго аргумента:

Выше использована функция со стрелкой, но также можно использовать регулярные функции:

Обновления состояния объединены

Когда вы вызываете setState(), React объединяет объект, который вы указываете, в текущее состояние. Например, ваше состояние может содержать несколько независимых переменных:

Затем вы можете самостоятельно обновлять их с помощью отдельных setState() вызовов:

Слияние неглубокое, поэтому this.setState() оставляет this.state.posts нетронутыми, но полностью заменяет this.state.comments.

Потоки данных

Ни родительский, ни дочерний компоненты не могут знать, является ли какой-либо компонент состоятельным или неактивным, и им не важно, определено ли оно как функция или класс. Вот почему состояние часто называют локальным или инкапсулированным. Он недоступен для любого компонента, кроме того, который владеет и устанавливает его. Компонент может выбрать передачу своего состояния вниз в качестве реквизита его дочерних компонентов:

Это также работает для пользовательских компонентов:

Источник

React.js state

last modified July 13, 2020

React.js state tutorial shows how to work with state in React.js

React.js

is a declarative, component-based JavaScript library for building user interfaces. React.js allows to build encapsulated components that manage their own state. These components can be used to create complex UIs.

React.js state

The state is built-in object in React components. In the state object we store property values that belong to the component. When the state object changes, the component re-renders. The state object is modified with the setState() function.

The developer should always try to make the state minimal. Also, the number of stateful components should be minimized.

React.js state example

We create a new React application with the npx create-react-app command.

We go to the newly created directory.

In the example, we have a title property in the state object. We use a checkbox to toggle the visibility of the title.

In the constructor, we set a default value for the title property.

The tooggleTitle() function toggles the contents of the title property. The property is updated with the setState() function.

We have a checkbox. On the click event the tooggleTitle() is called.

tag displays the title.

In the index.js file, we import the App component and render it into the root element.

This is the home page of the application. The component is rendered into the container with the root id.

We start the development server and navigate to the localhost:3000 to see the output.

In this tutorial, we have worked with the state object of a React component.

Источник

React.Component

Эта страница содержит подробный справочник API для определения классового компонента React. Предполагается, что вы знакомы с такими концепциями React, как компоненты и пропсы, а также состояние и жизненный цикл. Прочитайте про них, если вы этого не сделали.

React позволяет определять компоненты как классы или функции. В настоящее время классовые компоненты имеют больше возможностей. Они разобраны на этой странице. Чтобы определить такой компонент, необходимо отнаследоваться от React.Component :

Мы рекомендуем не создавать собственные классы базовых компонентов. В компонентах React повторное использование кода обычно достигается за счёт композиции, а не наследования.

React не заставляет вас использовать синтаксис классов из ES6. Вместо этого вы можете использовать модуль create-react-class или его аналоги. Посмотрите раздел Использование React без ES6, чтобы узнать больше.

Жизненный цикл компонента

Каждый компонент имеет несколько «методов жизненного цикла». Переопределение такого метода позволяет выполнять код на конкретном этапе этого процесса. Вы можете использовать эту диаграмму жизненного цикла как шпаргалку. Далее на странице полужирным шрифтом выделены самые распространённые методы жизненного цикла.

При создании экземпляра компонента и его вставке в DOM, следующие методы вызываются в установленном порядке:

Этот метод устарел. Не используйте его в новом коде.

Обновление происходит при изменении пропсов или состояния. Следующие методы вызываются в установленном порядке при повторном рендере компонента:

Эти методы устарели. Не используйте их в новом коде.

Этот метод вызывается при удалении компонента из DOM:

Следующие методы вызываются, если произошла ошибка в процессе рендеринга, методе жизненного цикла или конструкторе любого дочернего компонента.

В каждом компоненте доступны методы API:

Распространённые методы жизненного цикла

Методы в этом разделе охватывают большинство задач, с которыми вы столкнётесь при использовании React-компонентов. Для визуального представления вы можете использовать эту диаграмму жизненного цикла.

render() — единственный обязательный метод в классовом компоненте.

При вызове он проверяет this.props и this.state и возвращает один из следующих вариантов:

Функция render() должна быть чистой. Это означает, что она не изменяет состояние компонента, всегда возвращает один и тот же результат, не взаимодействует напрямую с браузером.

Взаимодействовать с браузером необходимо в componentDidMount() или других методах жизненного цикла. Чистый render() делает компонент понятным.

Вы можете не использовать конструктор в React-компоненте, если вы не определяете состояние или не привязываете методы.

Конструкторы в React обычно используют для двух целей:

Не копируйте пропсы в состояние! Это распространённая ошибка:

Прочитайте нашу статью в блоге про отсутствие необходимости в производном состоянии. Она описывает случаи, в которых вам необходимо состояние, зависящее от пропсов.

componentDidMount() вызывается сразу после монтирования (то есть, вставки компонента в DOM). В этом методе должны происходить действия, которые требуют наличия DOM-узлов. Это хорошее место для создания сетевых запросов.

componentDidUpdate() вызывается сразу после обновления. Не вызывается при первом рендере.

Метод позволяет работать с DOM при обновлении компонента. Также он подходит для выполнения таких сетевых запросов, которые выполняются на основании результата сравнения текущих пропсов с предыдущими. Если пропсы не изменились, новый запрос может и не требоваться.

Редко используемые методы жизненного цикла

Методы из этого раздела используются редко. В большинстве компонентов они не нужны, хотя иногда бывают полезны. Вы можете увидеть большинство приведённых ниже методов на этой диаграмме жизненного цикла, если наверху страницы нажмёте на чекбокс «Показать менее популярные методы жизненного цикла».

Этот метод нужен только для повышения производительности. Но не опирайтесь на его возможность «предотвратить» рендер, это может привести к багам. Вместо этого используйте PureComponent , который позволяет не описывать поведение shouldComponentUpdate() вручную. PureComponent поверхностно сравнивает пропсы и состояние и позволяет не пропустить необходимое обновление.

Этот метод существует для редких случаев, когда состояние зависит от изменений в пропсах. Например, это подойдёт для реализации компонента , который сравнивает свои предыдущие и следующие дочерние компоненты, чтобы решить, какой из них нужно анимировать.

Производное состояние приводит к сложному коду и делает ваши компоненты сложными для понимания. Убедитесь, что вы знакомы с простыми альтернативами:

Если вы хотите повторно использовать код между getDerivedStateFromProps() и другими методами класса, извлеките чистые функции пропсов и состояния компонента и поместите их вне определения класса.

Это применяется редко, но может быть полезно в таких интерфейсах, как цепочка сообщений в чатах, в которых позиция прокрутки обрабатывается особым образом.

Значение снимка (или null ) должно быть возвращено.

В примерах выше важно получить значение свойства scrollHeight в getSnapshotBeforeUpdate из-за того, что могут возникать задержки между этапами жизненного цикла «рендер» (например, render ) и «фиксирование» (например, getSnapshotBeforeUpdate и componentDidUpdate ).

Предохранители — это React-компоненты, которые перехватывают JavaScript-ошибки в любом месте их дочернего дерева компонентов. Затем логируют эти ошибки и отображают запасной интерфейс вместо «поломанного» дерева компонентов. Предохранители отлавливают ошибки при рендере, в методах жизненного цикла и в конструкторах всего дерева под ними.

Используйте предохранители только для обработки неожиданных исключений, не используйте их для управления потоком исполнения в вашем приложении.

Предохранители перехватывают ошибки в компонентах ниже по дереву. Предохранители не могут поймать ошибку внутри себя.

Этот метод жизненного цикла вызывается после возникновения ошибки у компонента-потомка. Он получает ошибку в качестве параметра и возвращает значение для обновления состояния.

Этот метод жизненного цикла вызывается после возникновения ошибки у компонента-потомка. Он получает два параметра:

componentDidCatch() вызывается во время этапа «фиксации», поэтому здесь можно использовать побочные эффекты. Метод можно использовать для логирования ошибок.

Обработка ошибок в методе componentDidCatch() отличается между React-сборками для продакшена и разработки.

Устаревшие методы жизненного цикла

Приведённые ниже методы жизненного цикла устарели. Их не рекомендуется использовать в новом коде, хотя они продолжают работать. Вы можете узнать больше о переходе с устаревших методов жизненного цикла в блоге.

Это единственный метод жизненного цикла, вызываемый при серверном рендеринге.

Использование этого метода жизненного цикла часто приводило к багам

Обратите внимание, если родительский компонент заставляет ваш компонент повторно рендериться, метод будет вызываться, даже если пропсы не изменились. Убедитесь, что сравниваете текущие и следующие значения, если вы хотите обрабатывать изменения.

UNSAFE_componentWillUpdate() вызывается непосредственно перед рендером при получении новых пропсов или состояния. В этом методе можно выполнить некоторую подготовку перед обновлением. Этот метод не вызывается при первом рендере.

В отличие от методов жизненного цикла, представленных выше (React вызывает их сам), методы, приведённые ниже, можно вызывать из компонентов.

setState() добавляет в очередь изменения в состоянии компонента. Также он указывает React, что компонент и его дочерние элементы должны быть повторно отрендерены с обновлённым состоянием. Этот метод используется для обновления интерфейса в ответ на обработчики событий и ответы сервера.

Эта форма записи setState() также асинхронна, и несколько вызовов в течение одного цикла могут быть объединены вместе. Например, вам нужно увеличить количество элементов несколько раз в одном цикле. Результат этого можно представить так:

Последующие вызовы будут переопределять значения из предыдущих вызовов того же цикла. Из-за этого количество увеличится только один раз. В случае, если следующее состояние зависит от текущего, мы рекомендуем использовать форму функции обновления:

Для более подробной информации смотрите:

Если props.color не передаётся, по умолчанию установится ‘синий’ :

Строка displayName используется в сообщениях для отладки. Обычно вам не нужно её явно указывать. По умолчанию используется имя функции или класса, указанное при определении компонента. Если вам нужно установить его явно, например, для отладки или создания компонента высшего порядка, посмотрите раздел Обёртка отображаемого имени для простой отладки.

this.props содержит свойства, которые были определены тем, кто вызывает этот компонент. Подробнее об этом можно узнать в разделе Компоненты и пропсы

Состояние содержит данные, специфичные для этого компонента. Они могут измениться со временем. Состояние определяется пользователем и должно быть простым объектом JavaScript.

Вам не нужно вставлять в состояние значение, если оно не используется для рендера или потока данных (например, идентификатор таймера). Такие значения можно определить как поля экземпляра компонента.

Дополнительную информацию можно найти в разделе Состояние и жизненный цикл.

Источник

Подъём состояния

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

В этом разделе мы создадим калькулятор температуры, вычисляющий вскипит ли вода при заданной температуре.

Кроме того, он рендерит BoilingVerdict для текущего значения поля ввода.

Добавление второго поля ввода

Добавим к полю ввода градусов Цельсия поле ввода по шкале Фаренгейта. Оба поля будут синхронизироваться.

Теперь можем изменить Calculator для рендера двух отдельных полей ввода температуры:

Сейчас у нас есть два поля ввода, но когда вы вводите температуру в одно из них, другое поле не обновляется. Это противоречит нашему требованию — мы хотим их синхронизировать.

Написание функций для конвертации температур

Во-первых, мы напишем две функции для конвертации градусов по шкале Цельсия в Фаренгейт и обратно:

Эти две функции конвертируют числа. Мы напишем ещё одну функцию, которая принимает строку с температурой ( temperature ) и функцию конвертации ( convert ) в качестве аргументов, и возвращает строку. Мы будем использовать эту функцию для вычисления значения одного поля ввода на основе значения из другого поля ввода.

Данная функция возвращает пустую строку при некорректном значении аргумента temperature и округляет возвращаемое значение до трёх чисел после запятой:

В настоящее время оба компонента TemperatureInput независимо хранят свои значения каждое в собственном локальном состоянии:

Однако мы хотим, чтобы эти два поля ввода синхронизировались друг с другом. Когда мы обновляем поле ввода градусов по Цельсию, поле ввода градусов по Фаренгейту должно отражать сконвертированную температуру и наоборот.

Давайте шаг за шагом посмотрим, как это работает.

Мы знаем, что пропсы доступны только для чтения. Когда temperature находилась во внутреннем состоянии, TemperatureInput мог просто вызвать this.setState() для изменения его значения. Однако теперь, когда temperature приходит из родительского компонента в качестве пропа, TemperatureInput не может контролировать его.

Теперь, когда TemperatureInput хочет обновить свою температуру, он вызывает this.props.onTemperatureChange :

Мы будем хранить текущие значения temperature и scale во внутреннем состоянии этого компонента. Это состояние, которое мы «подняли» от полей ввода, и теперь оно будет служить «источником истины» для них обоих. Это минимальное представление всех данных, про которое нам нужно знать для рендера обоих полей ввода.

Например, если мы вводим 37 как значение поля ввода для температуры по шкале Цельсия, состояние компонента Calculator будет:

Если позднее мы изменим поле для ввода градусов по шкале Фаренгейта на 212, состояние Calculator будет:

Поля ввода остаются синхронизированными, поскольку их значения вычисляются из одного и того же состояния:

Теперь, независимо от того, какое поле ввода вы редактируете, this.state.temperature и this.state.scale в Calculator обновляются. Одно из полей ввода получает значение как есть, поэтому введённые пользователем данные сохраняются, а значение другого поля ввода всегда пересчитывается на их основе.

Давайте посмотрим, что происходит, когда вы редактируете поле ввода:

Каждое обновление проходит через одни и те же шаги, поэтому поля ввода остаются синхронизированными.

Для любых изменяемых данных в React-приложении должен быть один «источник истины». Обычно состояние сначала добавляется к компоненту, которому оно требуется для рендера. Затем, если другие компоненты также нуждаются в нём, вы можете поднять его до ближайшего общего предка. Вместо того, чтобы пытаться синхронизировать состояние между различными компонентами, вы должны полагаться на однонаправленный поток данных.

Для подъёма состояния приходится писать больше «шаблонного» кода, чем при подходах с двусторонней привязкой данных, но мы получаем преимущество в виде меньших затрат на поиск и изолирование багов. Так как любое состояние «живёт» в каком-нибудь компоненте, и только этот компонент может его изменить, количество мест с возможными багами значительно уменьшается. Кроме того, вы можете реализовать любую пользовательскую логику для отклонения или преобразования данных, введённых пользователем.

Когда вы видите, что в UI что-то отображается неправильно, то можете воспользоваться расширением React Developer Tools. С помощью него можно проверить пропсы и перемещаться по дереву компонентов вверх до тех пор, пока не найдёте тот компонент, который отвечает за обновление состояния. Это позволяет отследить источник багов:

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *