Перейти к содержимому

Как размонтировать компонент react

  • автор:

Как правильно сделать размонтирование элемента (блока) в react.js?

В документации сказано, что componentWillUnmount запускается перед размонтирование элемента из DOM. Но как сделать размонтирование элента?
Говоря попросту мне надо один элемент заменить другим, которые привязаны к одному id или просто удалить элемент.
Как грамотно это сделать, что бы запускался componentWillUnmount у элемента, который удаляется из DOM?

  • Вопрос задан более трёх лет назад
  • 5267 просмотров

3 комментария

Оценить 3 комментария

Laiff

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

LB777

LB777 @LB777 Автор вопроса

Андрей Антропов: Мне как раз надо отписаться от слушателя. И как я понял, что componentWillUnmount сработает когда объект, скажем var FluxCart = React.createClass(<. >), будет размонтирован из DOM. Соответственно вопрос заключается в том как размонтировать (удалить) из DOM.

Сделать так что бы компонент не монтировался. Или тут что то супер сложное есть ? При каждом сетСтейте реакт обновляет все дерево компонентов ниже. Сделать сет стейт, передать пропс который укажет на то что бы мы не рендерели компонент

Как сделать componentWillUnmount в хуках

При использовании react portal создает див, куда кладется компонент, но при исчезновении(on Unmount), в DOM остается пустой див. Не красивенько, как исправить?

import < useEffect, useMemo >from 'react'; import <> from './styles'; import < createPortal >from 'react-dom'; const CollectionPreviewItem = ( < component >) => < const el = useMemo(()=>document.createElement ( 'div' ),[]); useEffect ( () => < document.body.appendChild ( el ); >, [ el ] ); return ( createPortal ( component, el ) ); >; export default CollectionPreviewItem;

Отслеживать
задан 1 апр 2020 в 21:21
Светлана Свиридова Светлана Свиридова
192 10 10 бронзовых знаков
Хук useEffect должен возвратить функцию, которая и будет вызываться при исчезновении элемента
1 апр 2020 в 21:38
return *; — то, что вам нужно (в useEffect)
1 апр 2020 в 21:40
@Denis Bubnov помогите пожалуйста ru.stackoverflow.com/questions/1109017/…
12 апр 2020 в 6:51

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

Хук useEffect представляет собой совокупность методов жизненного цикла React, таких как componentDidMount , componentDidUpdate , и componentWillUnmount .

Если вы хотите запустить эффект и сбросить его только один раз (при монтировании и размонтировании), вы можете передать пустой массив ( [] ) вторым аргументом. React посчитает, что ваш эффект не зависит от каких-либо значений из пропсов или состояния и поэтому не будет выполнять повторных запусков эффекта. Это не обрабатывается как особый случай — он напрямую следует из логики работы входных массивов.

Условное срабатывание эффекта: по-умолчанию эффекты запускаются после каждого завершённого рендера. Таким образом, эффект всегда пересоздаётся, если значение какой-то из зависимости изменилось. Однако в некоторых случаях это может быть излишним, чтобы реализовать это (не выполнять эффект каждый раз), передайте второй аргумент в useEffect , который является массивом значений, от которых зависит эффект.

Вот тут мы и подобрались к самому интересному — очистка эффекта. Часто эффекты создают ресурсы, которые необходимо очистить (или сбросить) перед тем, как компонент покидает экран, например подписку или идентификатор таймера. Чтобы сделать это, функция переданная в useEffect , может вернуть функцию очистки. То есть, если из хука useEffect вернуть функцию — она будет вызвана во время размонтирования ( componentWillUnmount ), вот так:

useEffect(() => < document.body.appendChild(el); return () =>< // Делайте в этом блоке что нужно, это и есть `componentWillUnmount` >; >, [el]); 

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

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

Изменение DOM, которое видно пользователю, должно запускаться синхронно до следующей отрисовки, чтобы пользователь не замечал визуального несоответствия. Для этих типов эффектов React предоставляет один дополнительный хук, называемый useLayoutEffect . Советую обратить ваше внимание на этот хук.

React.js для продолжающих

Итак, вы разобрались с основами React. Что дальше? А вот что — 5 концепций, изучение поднимет ваш скилл на новый уровень.

Обложка поста React.js для продолжающих

Итак, вы изучили основы React.js и теперь не знаете, что делать дальше? В статье рассмотрены 5 интересных вещей, которые поднимут ваши навыки и знания React.js на новый уровень.

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

Самой важной для понимания концепцией в этой статье является жизненный цикл компонента. Её суть ясна из названия — она описывает жизнь компонента. Как и мы, компоненты рождаются, что-то делают во время своего пребывания на бренной земле (сервере), а потом умирают.

Однако жизненные этапы компонентов немного отличаются от наших. Вот как они выглядят:

Каждый раскрашенный горизонтальный прямоугольник отражает метод жизненного цикла (за исключением «React обновляет DOM и ссылки»). Столбцы отражают разные этапы жизни компонента.

Компонент может находиться только на одном этапе. Всё начинается с монтирования и продолжается обновлением. Компонент постоянно обновляется, пока не будет удалён из виртуального DOM. Затем компонент переходит на этап размонтирования и удаляется из DOM.

Методы жизненного цикла позволяют запускать код в определённые моменты жизни компонента или в ответ на какие-то изменения в ней.

Пройдёмся по каждому этапу жизни компонента и связанным методам.

Монтирование

Так как компоненты на основе классов являются классами (отсюда и название), первый запускаемый метод — это constructor() . Как правило, в constructor() мы инициализируем состояние компонента.

Затем компонент запускает getDerivedStateFromProps() . Опустим этот метод, так как он не очень полезный.

После этого наступает очередь метода render() , который возвращает JSX. Теперь React «монтируется» в DOM.

Наконец, запускается метод componentDidMount() . Здесь выполняются все асинхронные вызовы к базам данных или напрямую управляется DOM. Компонент рождён.

Обновление

Этот этап запускается при каждом изменении состояния или свойств. Как и при монтировании, вызывается метод getDerivedStateFromProps() , но в этот раз без constructor() .

Затем запускается shouldComponentUpdate() . Здесь можно сравнивать старые свойства или состояния с новым набором свойств или состояний. Можно указать, нужно ли заново отображать компонент, вернув true или false . Это позволит сделать приложение более эффективным за счёт уменьшения количества лишних отображений. Если shouldComponentUpdate() возвращает false , на этом этап обновлений завершается.

В противном случае React заново отобразится, а затем запускается getSnapshotBeforeUpdate() . Этот метод тоже не очень полезен. Далее React запускает componentDidUpdate() . Как и componentDidMount() , его можно использовать для асинхронных вызовов или управления DOM.

Размонтирование

Компонент прожил хорошую жизнь, однако всё хорошее рано или поздно кончается. Размонтирование — последний этап жизни компонента. При удалении компонента из DOM React запускает componentWillUnmount() прямо перед удалением. Этот метод используется для закрытия всех открытых соединений вроде веб-сокетов или тайм-аутов.

Другие методы жизненного цикла

Прежде чем мы перейдём к другой теме, давайте вскользь упомянем forceUpdate() и getDerivedStateFromError() .

forceUpdate() — метод, который напрямую вызывает повторное отображение. Хотя у него и есть несколько применений, обычно его следует избегать.

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

Следующий фрагмент кода с CodePen показывает этапы стадии монтирования:

class App extends React.Component < constructor(props) < super(props) console.log('Hello from constructor') >static getDerivedStateFromProps() < console.log('Hello from before rendering') >componentDidMount() < console.log('Hello from after mounting') >render() < console.log('Hello from render') return ( Hello! ); >> ReactDOM.render( , document.getElementById('app') ); 
Hello from constructor Hello from before rendering Hello from render Hello from after mounting 

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

Компоненты высшего порядка

Возможно, вы уже использовали компоненты высшего порядка (КВП). Например, функция Redux connection() возвращает КВП. Но что из себя представляют эти компоненты?

Из документации React:

Компонент высшего порядка — это функция, которая принимает компонент и возвращает новый компонент.

Возвращаясь к функции connect() , посмотрим на следующий фрагмент кода:

const hoc = connect(state => state) const WrappedComponent = hoc(SomeComponent) 

При вызове connect() мы получаем КВП, который можно использовать для того, чтобы обернуть компонент. Затем мы просто передаём наш компонент в КВП и начинаем использовать возвращаемый им компонент.

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

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

Вот как всё это может выглядеть без КВП:

class RegularComponent extends React.Component < render() < if (this.props.isLoggedIn) < return Hi >return You're not logged in :С > > // повторяющийся код! class OtherRegularComponent extends React.Component < render() < if (this.props.isLoggedIn) < return Hi >return You're not logged in :С > > // обратите внимание, что для функционального компонента нам нужна другая логика const FunctionalComponent = (< isLoggedIn >) => ( isLoggedIn ? Hi There : You're not logged in :С ) 

Тонна повторяющегося кода и запутанная логика!

И вот как код преобразится с использованием КВП:

function AuthWrapper(WrappedComponent) < return class extends React.Component < render() < if (this.props.isLoggedIn) < return >return You're not logged in :С > > > class RegularComponent extends React.Component < render() < return hi >> class OtherRegularComponent extends React.Component < render() < return Hello >> const FunctionalComponent = () => (Hi There) const WrappedOne = AuthWrapper(RegularComponent) const WrappedTwo = AuthWrapper(OtherRegularComponent) const WrappedThree = AuthWrapper(FunctionalComponent) 

Вот CodePen со всем кодом.

Глядя на этот код можно понять, что компоненты могут оставаться очень простыми, даже, если будут производить аутентификацию. Компонент AuthWrapper содержит всю логику аутентификации. Всё, что он делает, — смотрит на свойство isLoggedIn и возвращает WrappedComponent или тег

в зависимости от присвоенного свойству значения.

Как видите, КВП очень полезны, так как позволяют повторно использовать код. Скоро мы к ним вернёмся.

Состояние и setState()

Большинство из вас скорее всего уже использовали состояния React, они были даже в примере с КВП. Однако важно понимать, что при смене состояния React запустит процесс повторного отображения компонента (если не указать иное в shouldComponentUpdate() ).

Поговорим о том, как можно изменить состояние. Единственный способ сделать это — использовать метод setState() . Он принимает объект и объединяет его с текущим состоянием. Помимо этого есть ещё несколько вещей, которые следует знать.

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

React.js для продолжающих 1

Взглянув на эту картинку можно увидеть, что мы сначала вызываем setState() , а затем console.log() . Новое значение переменной counter должно быть равно 1, однако выводится 0. Что если мы хотим получить доступ к новому состоянию после того, как setState() действительно обновит состояние?

Тут мы плавно переходим к следующей вещи, которую нужно знать о setState() — этот метод может принимать callback-функцию. Исправим наш код:

React.js для продолжающих 2

Отлично, всё работает, на этом можно закончить, да? Не совсем. На самом деле, в данном случае мы не используем setState() корректно. Вместо передачи объекта мы передадим методу функцию. Так обычно делается, когда для установки нового состояния используется текущее. Если это не ваш случай, то смело продолжайте передавать объект в setState() . Исправим код ещё раз:

React.js для продолжающих 3

Вот CodePen для этого примера.

В чём смысл передачи функции вместо объекта? Поскольку setState() асинхронный, полагаться на него при создании нового значения немного рискованно. Например, к моменту запуска одного setState() другой setState() мог уже обновить состояние. Передача функции в setState() даёт два преимущества:

  1. Это позволяет создавать статичную копию состояния, которое никогда не изменится само по себе.
  2. Это поместит вызовы setState() в очередь, поэтому они будут запускаться по порядку.

Посмотрим на следующий пример, в котором попытаемся увеличить счётчик на 2, используя два последовательных вызова setState() :

React.js для продолжающих 4

Сравните с кодом ниже:

React.js для продолжающих 5

CodePen для этого кода.

На первом изображении обе функции setState() напрямую используют this.state.counter , который, как мы узнали ранее, останется со значением 0 после вызова первого setState() . Таким образом, конечное значение равно 1, а не 2, так обе функции setState() устанавливают значение счётчика равным 1.

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

Вот и всё, что вам нужно знать о состояниях React.

Контекст

Контекст React — это глобальное состояние для компонентов.

API контекста React даёт возможность создавать глобальные объекты компонентов, которые будут доступны любому компоненту. Это позволяет обмениваться данными без необходимости передавать свойства по всему дереву DOM.

Как использовать контекст?

Сначала создадим объект контекста:

const ContextObject = React.createContext(< foo: "bar" >) 

В документации React установка контекста в компоненте выглядит так:

MyClass.contextType = MyContext; 

Однако в CodePen (React 16.4.2) это не сработало. Вместо этого мы воспользуемся КВП, чтобы использовать контекст образом, похожим на тот, что рекомендует Дэн Абрамов.

function contextWrapper(WrappedComponent, Context) < return class extends React.Component < render() < return ( < context =>> ) > > > 

Здесь мы оборачиваем компонент в компонент Context.Consumer и передаём в контекст в качестве свойства.

Теперь мы можем написать что-то такое:

class Child extends React.Component < render() < console.log(this.props.context) return Child >> const ChildWithContext = contextWrapper(Child, AppContext) 

И у нас будет доступ к foo из объекта контекста в свойствах.

А как сменить контекст? Это уже немного сложнее, однако мы можем ещё раз использовать КВП и получить что-то такое:

function contextProviderWrapper(WrappedComponent, Context, initialContext) < return class extends React.Component < constructor(props) < super(props) this.state = < . initialContext >> // определяем изменения состояния changeContext = () => < this.setState(< foo: 'baz' >) > render() < return ( ) >> > 

Сначала мы берём исходное состояние контекста — объект, переданный в React.createContext() — и используем его в качестве состояния компонента-обёртки. Затем мы определяем все методы, которые будем использовать для смены состояния. Наконец, оборачиваем наш компонент в компонент Context.Provider . Мы передаём состояние и функцию в свойство value . Теперь они будут в контексте у всех наследников, обёрнутых в компонент Context.Consumer .

Собираем всё воедино (КВП опущены для краткости):

const initialContext = < foo: 'bar' >const AppContext = React.createContext(initialContext); class Child extends React.Component < render() < return ( Click ) > > const ChildWithContext = contextConsumerWrapper(Child, AppContext) const ChildWithProvide = contextProviderWrapper(ChildWithContext, AppContext, initialContext) class App extends React.Component < render() < return ( ); >> 

Теперь у дочернего компонента есть доступ к глобальному контексту. У него есть возможность изменить значение атрибута foo в состоянии на baz .

CodePen со всем кодом по теме контекста.

Не пропускайте новостей React!

React активно развивается. Например, в React 16.3 некоторые методы жизненного цикла были упразднены, в React 16.6 появились асинхронные компоненты, а в React 16.7 появились хуки, цель которых — полностью заменить компоненты на основе классов. Следите за развитем React и растите вместе с ним!

Состояние и жизненный цикл

На этой странице представлены понятия «состояние» (state) и «жизненный цикл» (lifecycle) React-компонентов. Подробный справочник API компонентов находится по этой ссылке.

В качестве примера рассмотрим идущие часы из предыдущего раздела. В главе Рендеринг элементов мы научились обновлять UI только одним способом — вызовом root.render() :

const root = ReactDOM.createRoot(document.getElementById('root')); function tick()  const element = ( div> h1>Привет, мир!h1> h2>Сейчас new Date().toLocaleTimeString()>.h2> div> ); root.render(element);> setInterval(tick, 1000);

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

Для начала, извлечём компонент, показывающий время:

const root = ReactDOM.createRoot(document.getElementById('root')); function Clock(props)  return ( div>  h1>Привет, мир!h1>  h2>Сейчас props.date.toLocaleTimeString()>.h2>  div> ); > function tick()   root.render(Clock date=new Date()> />);> setInterval(tick, 1000);

Проблема в том, что компонент Clock не обновляет себя каждую секунду автоматически. Хотелось бы спрятать логику, управляющую таймером, внутри самого компонента Clock .

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

root.render(Clock />);

Для этого добавим так называемое «состояние» (state) в компонент Clock .

«Состояние» очень похоже на уже знакомые нам пропсы, отличие в том, что состояние контролируется и доступно только конкретному компоненту.

Преобразование функционального компонента в классовый

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

  1. Создаём ES6-класс с таким же именем, указываем React.Component в качестве родительского класса
  2. Добавим в класс пустой метод render()
  3. Перенесём тело функции в метод render()
  4. Заменим props на this.props в теле render()
  5. Удалим оставшееся пустое объявление функции
class Clock extends React.Component  render()  return ( div> h1>Привет, мир!h1> h2>Сейчас this.props.date.toLocaleTimeString()>.h2> div> ); > >

Теперь Clock определён как класс, а не функция.

Метод render будет вызываться каждый раз, когда происходит обновление. Так как мы рендерим в один и тот же DOM-контейнер, мы используем единственный экземпляр класса Clock — поэтому мы можем задействовать внутреннее состояние и методы жизненного цикла.

Добавим внутреннее состояние в класс

Переместим date из пропсов в состояние в три этапа:

  1. Заменим this.props.date на this.state.date в методе render() :
class Clock extends React.Component  render()  return ( div> h1>Привет, мир!h1> h2>Сейчас this.state.date.toLocaleTimeString()>.h2>  div> ); > >
  1. Добавим конструктор класса, в котором укажем начальное состояние в переменной this.state :
class Clock extends React.Component  constructor(props)  super(props); this.state = date: new Date()>; > render()  return ( div> h1>Привет, мир!h1> h2>Сейчас this.state.date.toLocaleTimeString()>.h2> div> ); > >

Обратите внимание, что мы передаём props базовому (родительскому) конструктору:

 constructor(props)   super(props); this.state = date: new Date()>; >

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

  1. Удалим проп date из элемента :
root.render(Clock />);

Позже мы вернём код таймера обратно и на этот раз поместим его в сам компонент.

Результат выглядит следующим образом:

class Clock extends React.Component   constructor(props)  super(props); this.state = date: new Date()>; > render()  return ( div> h1>Привет, мир!h1> h2>Сейчас this.state.date.toLocaleTimeString()>.h2>  div> ); > > const root = ReactDOM.createRoot(document.getElementById('root')); root.render(Clock />);

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

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

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

Первоначальный рендеринг компонента в DOM называется «монтирование» (mounting). Нам нужно устанавливать таймер всякий раз, когда это происходит.

Каждый раз когда DOM-узел, созданный компонентом, удаляется, происходит «размонтирование» (unmounting). Чтобы избежать утечки ресурсов, мы будем сбрасывать таймер при каждом «размонтировании».

Объявим специальные методы, которые компонент будет вызывать при монтировании и размонтировании:

class Clock extends React.Component  constructor(props)  super(props); this.state = date: new Date()>; > componentDidMount()  > componentWillUnmount()  > render()  return ( div> h1>Привет, мир!h1> h2>Сейчас this.state.date.toLocaleTimeString()>.h2> div> ); > >

Эти методы называются «методами жизненного цикла» (lifecycle methods).

Метод componentDidMount() запускается после того, как компонент отрендерился в DOM — здесь мы и установим таймер:

 componentDidMount()   this.timerID = setInterval( () => this.tick(), 1000 ); >

Обратите внимание, что мы сохраняем ID таймера в this ( this.timerID ).

Поля this.props и this.state в классах — особенные, и их устанавливает сам React. Вы можете вручную добавить новые поля, если компоненту нужно хранить дополнительную информацию (например, ID таймера).

Теперь нам осталось сбросить таймер в методе жизненного цикла componentWillUnmount() :

 componentWillUnmount()   clearInterval(this.timerID); >

Наконец, реализуем метод tick() . Он запускается таймером каждую секунду и вызывает this.setState() .

this.setState() планирует обновление внутреннего состояния компонента:

class Clock extends React.Component  constructor(props)  super(props); this.state = date: new Date()>; > componentDidMount()  this.timerID = setInterval( () => this.tick(), 1000 ); > componentWillUnmount()  clearInterval(this.timerID); > tick()  this.setState( date: new Date() >); > render()  return ( div> h1>Привет, мир!h1> h2>Сейчас this.state.date.toLocaleTimeString()>.h2> div> ); > > const root = ReactDOM.createRoot(document.getElementById('root')); root.render(Clock />);

Теперь часы обновляются каждую секунду.

Давайте рассмотрим наше решение и разберём порядок, в котором вызываются методы:

  1. Когда мы передаём в root.render() , React вызывает конструктор компонента. Clock должен отображать текущее время, поэтому мы задаём начальное состояние this.state объектом с текущим временем. Позже мы обновим это состояние.
  2. React вызывает метод render() компонента Clock . Таким образом React узнаёт, что отобразить на экране. Далее React обновляет DOM так, чтобы он соответствовал выводу рендера Clock .
  3. Как только вывод рендера Clock вставлен в DOM, React вызывает метод жизненного цикла componentDidMount() . Внутри него компонент Clock указывает браузеру установить таймер, который будет вызывать tick() раз в секунду.
  4. Таймер вызывает tick() ежесекундно. Внутри tick() мы просим React обновить состояние компонента, вызывая setState() с текущим временем. React реагирует на изменение состояния и снова запускает render() . На этот раз this.state.date в методе render() содержит новое значение, поэтому React заменит DOM. Таким образом компонент Clock каждую секунду обновляет UI.
  5. Если компонент Clock когда-либо удалится из DOM, React вызовет метод жизненного цикла componentWillUnmount() и сбросит таймер.

Как правильно использовать состояние

Важно знать три детали о правильном применении setState() .

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

В следующем примере повторного рендера не происходит:

// Неправильно this.state.comment = 'Привет';

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

// Правильно this.setState(comment: 'Привет'>);

Конструктор — это единственное место, где вы можете присвоить значение this.state напрямую.

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

React может сгруппировать несколько вызовов setState() в одно обновление для улучшения производительности.

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

Например, следующий код может не обновить счётчик:

// Неправильно this.setState( counter: this.state.counter + this.props.increment, >);

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

// Правильно this.setState((state, props) => ( counter: state.counter + props.increment >));

В данном примере мы использовали стрелочную функцию, но можно использовать и обычные функции:

// Правильно this.setState(function(state, props)  return  counter: state.counter + props.increment >; >);

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

Когда мы вызываем setState() , React объединит аргумент (новое состояние) c текущим состоянием.

Например, состояние может состоять из нескольких независимых полей:

 constructor(props)  super(props); this.state =   posts: [], comments: [] >; >

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

 componentDidMount()  fetchPosts().then(response =>  this.setState(  posts: response.posts >); >); fetchComments().then(response =>  this.setState(  comments: response.comments >); >); >

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

Однонаправленный поток данных

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

Состояние часто называют «локальным», «внутренним» или инкапсулированным. Оно доступно только для самого компонента и скрыто от других.

Компонент может передать своё состояние вниз по дереву в виде пропсов дочерних компонентов:

FormattedDate date=this.state.date> />

Компонент FormattedDate получает date через пропсы, но он не знает, откуда они взялись изначально — из состояния Clock , пропсов Clock или просто JavaScript-выражения:

function FormattedDate(props)  return h2>Сейчас props.date.toLocaleTimeString()>.h2>; >

Это, в общем, называется «нисходящим» («top-down») или «однонаправленным» («unidirectional») потоком данных. Состояние всегда принадлежит определённому компоненту, а любые производные этого состояния могут влиять только на компоненты, находящиеся «ниже» в дереве компонентов.

Если представить иерархию компонентов как водопад пропсов, то состояние каждого компонента похоже на дополнительный источник, который сливается с водопадом в произвольной точке, но также течёт вниз.

Чтобы показать, что все компоненты действительно изолированы, создадим компонент App , который рендерит три компонента :

function App()  return ( div> Clock />  Clock />  Clock />  div> ); >

У каждого компонента Clock есть собственное состояние таймера, которое обновляется независимо от других компонентов.

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

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

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