Руководство по рендеренгу в React
Render не перерисовывает DOM дерево, его задача — формирование "виртуального" дерева. Если полученное дерево совпадает с предыдущим, то обновления DOM не произойдет.
Процесс обновления UI в React приложении состоит из трех фаз:
Render — формирование текущего дерева компонентов на основании их свойств (props) и состояния (state)
Reconciliation — сравнение и вычисление отличий с предыдущим деревом
Commit — обновление DOM
После commit фазы, React синхронно запускает lifecycle методы componentDidMount() , componentDidUpdate() , и хук useLayoutEffect() . И затем асинхронно хук useEffect() .
Рендер использует функцию React.createElement() , которая возвращает js объект, описывающий представление компонента:
После первичного рендеринга и отображения приложения в DOM дереве, повторный рендер может быть вызван по одной из следующих причин.
Для классовых компонентов:
- this.setState()
- this.forceUpdate()
Для функциональных компонентов:
- useState
- useReducer
- Рендер родителя вызовет рендер всех его дочерних элементов (стандартное поведение, но возможна оптимизация)
- повторный рендеринг будет вызван, если повторно запустить ReactDOM.render(<App />) , что эквивалентно forceUpdate() на корневом компоненте.
Рендер дочерних компонентов
По умолчанию, если рендерится родительский компонент, то все его дочерние компоненты будут перерендерены, даже если их props не изменились.
Рендер "дешевая" операция, по сравнению с обновлением DOM дерева. Если, выполняя рендер, React увидит, что текущий результат рендера совпадает с предыдущим, то обновление DOM не произойдет (фаза commit будет пропущена). Но процесс рендеринга и сравнения (фазы render и reconciliation) тоже занимают некоторое время, и в ряде случаев можно пропустить их для оптимизации производительности.
Оптимизация рендеринга заключается в том, чтобы не делать его без необходимости.
Для предотвращения лишнего рендера могут быть использованы:
- React.Component.shouldComponentUpdate — метод жизненного цикла классового компонента, если он вернет false то рендер не будет запущен.
- React.PureComponent — класс, реализующий типовой shouldComponentUpdate .
- React.memo() — HOC, который предотвращает повторный рендер, если входные props не изменились
Используйте React.memo() на родительском компоненте, чтобы остановить каскадный рендер всех дочерних компонентов.
Мемоизация тоже имеет свою цену и применять ее следует при необходимости. По этой причине, стандартно, React компоненты не мемоизированы.
Стандартные методы оптимизации сравниваются объекты и функции в props как ссылки, и если ссылка меняется, то произойдет рендер, даже если новый объект эквивалентен предыдущему:
Любой рендер <ParentComponent /> вызовет рендер <MemoizedChildComponent /> . Причина в том, что при рендере <ParentComponent /> , функция onClick будет создаваться заново. Для того, чтобы это предотвратить, нужно использовать специальные методы, которые сохраняют ссылки на неизменные объекты между рендерами.
Данная особенность касается функциональных компонентов, так как экземпляр классового компонента и ссылки на его методы находятся в памяти и не меняются.
Избегайте случайной инициализации объекта или функции непосредственно в props, это является распространенной ошибкой:
Чтобы в функциональном компоненте сохранить ссылки на объекты между рендерами, используйте хуки:
- useMemo()
- useCallback()
Хуки useMemo() и useCallback() принимают вторым аргументом массив зависимостей. Изменение зависимостей приведет к перерасчету значения, которое возвращает хук.
Не производите замер производительности в develop режиме, только в production сборке.
Полезные статьи по профилированию производительности:
React's Context API обеспечивает передачу переменных в дерево компонентов, без их непосредственной передачи в props данных компонентов.
Context не является стейт-менеджером. Вы должны сами управлять значениями, которые передаются в Контекст. Обычно это достигается созданием компонента со стейтом, который устанавливает из него переменные Контекста.
Для функциональных компонентов хук:
Если значение Контекст обновлено, то все компоненты, которые его используют, будут перерендерены. Нет способа это изменить.
Если в Контекст передан массив, или объект, то при его изменении, будут перерендерен каждый компонент, использующий данный Контекст. Даже если изменилась только часть объекта, которую непосредственно этот компонент не использует.
Следует помнить, что рендер родительского компонента, вызывает рендер всех его дочерних компонентов, по этому:
Компонент, который находится под Context Provider, почти гарантированно должен использовать React.memo.
Далее рассмотрим сценарий обновления компонентов, использующих мемоизацию и Контекст.
Контекст и мемоизация
Если выполнить setA(42) произойдет следующее:
- Рендер ParentComponent
- Создается ссылка на contextValue
- React понимает, что MyContext.Provider получил новое значение и его потребителей нужно обновить.
- React попытается рендерить MemoizedChildComponent , который обернут в React.memo. Так как свойства не изменились, то сработает мемоизация и React не станет повторно рендерить ChildComponent .
- Тем не менее, обновился MyContext.Provider, и могут быть компоненты ниже по дереву, которые его используют. React продолжит обход и увидит GrandchildComponent . GrandchildComponent использует контекст, и так как контекст обновился, React перерендерит GrandchildComponent.
- Так как GrandchildComponent рендерится, React двигается дальше и рендерит все, что в нем находится. Таким образом, React повторно рендерит GreatGrandchildComponent .
React-Redux и Context
Redux и Контекст — разные инструменты и делают разную работу.
Несмотря на то, что Redux использует Контекст, имеются существенные отличия. Redux передает в Контекст экземпляр хранилища, ссылка на экземпляр всегда неизменна. Таким образом, React не обновляет компоненты при изменении значений в хранилище стандартным способом. Логикой обновления компонентов занимается непосредственно модуль, связывающий React и Redux.
Обновление происходит за счет того, что UI компоненты, подключенные к Redux, подписываются на изменение хранилища. Когда меняется значение в хранилище, для каждого подписчика вызывается callback, сравнивающий старое и новое значение релевантное для данного подписчика, которое используется в его mapState() или useSelector() . Если значение изменилось, то для данного компонента форсированно выполняется рендер.
Контекст, при изменении значения в провайдере, вызывает рендер для каждого компонента. Redux вызывает рендер только для тех компонентов, которые непосредственно используют измененные значения. Но при использовании Redux, для каждого компонента запускается селектор и сравниваются значения.
Обычно реализация в Redux (запуск селекторов, сравнение старого и нового значения, рендеринг если значение изменилось) работает быстрее, чем стандартная реализация на Контексте (полный перерендер дерева). Но при наличии сложных вычислений в селекторах, или если селекторы случайно возвращают новую ссылку, возможна потеря производительности.
Connect и useSelector
Используйте React.memo() в компонентах с useSelector() , чтобы остановить нежелательную нисходящую последовательность рендеров. При использовании connect() React сделает это за вас.
Функция connect() создает HOC, который подписывает компонент на изменение хранилища, выполняет работу по mapState() , mapDispatch() , передает комбинированные свойства в компонент и контролирует, чтобы рендер вызывался при изменении свойств, на которые подписан компонент, а не при изменении любого свойства в хранилище.
connect() HOC предотвращает повторный рендеринг, аналогично PureComponent и React.memo() , если входные свойства не изменились. Но стоит помнить, что помимо собственных свойств, сюда добавляется mapState() , и если он возвратит новую ссылку, то это вызовет рендер.
Свойства, которые передаются HOC'ом в компонент, формируются по такому принципу:
Хук useSelector() запускается внутри функционального компонента и не имеет возможности остановить рендер данного компонента, если рендерится его родительский компонент.
Как заставить react обновить компонент
Эта страница содержит подробный справочник API для определения классового компонента React. Предполагается, что вы знакомы с такими концепциями React, как компоненты и пропсы, а также состояние и жизненный цикл. Прочитайте про них, если вы этого не сделали.
React позволяет определять компоненты как классы или функции. В настоящее время классовые компоненты имеют больше возможностей. Они разобраны на этой странице. Чтобы определить такой компонент, необходимо отнаследоваться от React.Component :
Единственный обязательный метод в подклассе React.Component – render() . Все остальные методы, описанные ниже, являются необязательными.
Мы рекомендуем не создавать собственные классы базовых компонентов. В компонентах React повторное использование кода обычно достигается за счёт композиции, а не наследования.
Примечание:
React не заставляет вас использовать синтаксис классов из ES6. Вместо этого вы можете использовать модуль create-react-class или его аналоги. Посмотрите раздел Использование React без ES6, чтобы узнать больше.
Жизненный цикл компонента
Каждый компонент имеет несколько «методов жизненного цикла». Переопределение такого метода позволяет выполнять код на конкретном этапе этого процесса. Вы можете использовать эту диаграмму жизненного цикла как шпаргалку. Далее на странице полужирным шрифтом выделены самые распространённые методы жизненного цикла.
При создании экземпляра компонента и его вставке в DOM, следующие методы вызываются в установленном порядке:
Обновление происходит при изменении пропсов или состояния. Следующие методы вызываются в установленном порядке при повторном рендере компонента:
Этот метод вызывается при удалении компонента из DOM:
Следующие методы вызываются, если произошла ошибка в процессе рендеринга, методе жизненного цикла или конструкторе любого дочернего компонента.
Другие методы API
В каждом компоненте доступны методы API:
Распространённые методы жизненного цикла
Методы в этом разделе охватывают большинство задач, с которыми вы столкнётесь при использовании React-компонентов. Для визуального представления вы можете использовать эту диаграмму жизненного цикла.
render() – единственный обязательный метод в классовом компоненте.
При вызове он проверяет this.props и this.state и возвращает один из следующих вариантов:
- Элемент React. Обычно создаётся с помощью JSX. Указывает React, что рендерить: DOM-узел или пользовательский компонент. Например, <div /> или <MyComponent /> .
- Массивы и фрагменты. Возвращает несколько элементов из render() . Подробнее про фрагменты.
- Порталы. Рендерит несколько дочерних элементов в другое поддерево DOM. Подробнее про порталы.
- Строки и числа. Рендерит текстовые DOM-узлы.
- Booleans или null . Ничего не рендерит. (Обычно необходим для поддержки паттерна return test && <Child /> , где test – логическое значение.)
Функция render() должна быть чистой. Это означает, что она не изменяет состояние компонента, всегда возвращает один и тот же результат, не взаимодействует напрямую с браузером.
Взаимодействовать с браузером необходимо в componentDidMount() или других методах жизненного цикла. Чистый render() делает компонент понятным.
Вы можете не использовать конструктор в React-компоненте, если вы не определяете состояние или не привязываете методы.
Конструктор компонента React вызывается до того, как компонент будет примонтирован. В начале конструктора необходимо вызывать super(props) . Если это не сделать, this.props не будет определён. Это может привести к багам.
Конструкторы в React обычно используют для двух целей:
- Инициализация внутреннего состояния через присвоение объекта this.state .
- Привязка обработчиков событий к экземпляру.
Вы не должны вызывать setState() в constructor() . Если вам нужно внутреннее состояние, присвойте начальное состояние this.state прямо в конструкторе.
Конструктор — единственное место, где можно напрямую изменять this.state . В остальных методах необходимо использовать this.setState() .
Не используйте побочные эффекты или подписки в конструкторе. Вместо этого используйте componentDidMount() .
Примечание:
Не копируйте пропсы в состояние! Это распространённая ошибка:
Проблема в том, что это излишне и приводит к багам (обновления в пропе color не будут зафиксированы в состоянии). Вместо этого используйте this.props.color .
Используйте данный подход, если вы намеренно хотите игнорировать обновления пропсов. В таком случае лучше переименовать проп в initialColor или defaultColor . После этого вы сможете заставить компонент «сбросить» своё внутреннее состояние, изменив свой ключ, когда это будет необходимо.
Прочитайте нашу статью в блоге про отсутствие необходимости в производном состоянии. Она описывает случаи, в которых вам необходимо состояние, зависящее от пропсов.
componentDidMount() вызывается сразу после монтирования (то есть, вставки компонента в DOM). В этом методе должны происходить действия, которые требуют наличия DOM-узлов. Это хорошее место для создания сетевых запросов.
Этот метод подходит для настройки подписок. Но не забудьте отписаться от них в componentWillUnmount() .
Вы можете сразу вызвать setState() в componentDidMount() . Это вызовет дополнительный рендер перед тем, как браузер обновит экран. Гарантируется, что пользователь не увидит промежуточное состояние, даже если render() будет вызываться дважды. Используйте этот подход с осторожностью, он может вызвать проблемы с производительностью. В большинстве случаев начальное состояние лучше объявить в constructor() . Однако, это может быть необходимо для случаев, когда нужно измерить размер или положение DOM-узла, на основе которого происходит рендер. Например, для модальных окон или всплывающих подсказок.
componentDidUpdate() вызывается сразу после обновления. Не вызывается при первом рендере.
Метод позволяет работать с DOM при обновлении компонента. Также он подходит для выполнения таких сетевых запросов, которые выполняются на основании результата сравнения текущих пропсов с предыдущими. Если пропсы не изменились, новый запрос может и не требоваться.
В componentDidUpdate() можно вызывать setState() , однако его необходимо обернуть в условие, как в примере выше, чтобы не возник бесконечный цикл. Вызов setState() влечет за собой дополнительный рендер, который незаметен для пользователя, но может повлиять на производительность компонента. Вместо «отражения» пропсов в состоянии рекомендуется использовать пропсы напрямую. Подробнее о том, почему копирование пропсов в состояние вызывает баги.
В тех редких случаях когда реализован метод жизненного цикла getSnapshotBeforeUpdate() , его результат передаётся componentDidUpdate() в качестве третьего параметра snapshot .
Примечание:
componentDidUpdate() не вызывается, если shouldComponentUpdate() возвращает false .
componentWillUnmount() вызывается непосредственно перед размонтированием и удалением компонента. В этом методе выполняется необходимый сброс: отмена таймеров, сетевых запросов и подписок, созданных в componentDidMount() .
Не используйте setState() в componentWillUnmount() , так как компонент никогда не рендерится повторно. После того, как экземпляр компонента будет размонтирован, он никогда не будет примонтирован снова.
Редко используемые методы жизненного цикла
Методы из этого раздела используются редко. В большинстве компонентов они не нужны, хотя иногда бывают полезны. Вы можете увидеть большинство приведённых ниже методов на этой диаграмме жизненного цикла, если наверху страницы нажмёте на чекбокс «Показать менее популярные методы жизненного цикла».
Используйте shouldComponentUpdate() , чтобы указать необходимость следующего рендера на основе изменений состояния и пропсов. По умолчанию происходит повторный рендер при любом изменении состояния. В большинстве случаев вы должны полагаться на это поведение.
shouldComponentUpdate() вызывается перед рендером, когда получает новые пропсы или состояние. Значение по умолчанию равно true . Этот метод не вызывается при первом рендере или когда используется forceUpdate() .
Этот метод нужен только для повышения производительности. Но не опирайтесь на его возможность «предотвратить» рендер, это может привести к багам. Вместо этого используйте PureComponent , который позволяет не описывать поведение shouldComponentUpdate() вручную. PureComponent поверхностно сравнивает пропсы и состояние и позволяет не пропустить необходимое обновление.
Если вы уверены, что хотите написать его вручную, вы можете сравнить this.props с nextProps , а this.state с nextState . Верните false чтобы пропустить обновление React. Возврат false не предотвращает повторный рендер дочерних компонентов при изменении их состояния.
Мы не рекомендуем делать глубокое сравнение или использовать JSON.stringify() в shouldComponentUpdate() . Это неэффективно и плохо влияет на производительность.
В настоящее время, если shouldComponentUpdate() возвращает false , то UNSAFE_componentWillUpdate() , render() и componentDidUpdate() не будут вызваны. В будущем React может рассматривать shouldComponentUpdate() как подсказку, а не строгое указание. В таком случае возврат false сможет привести к повторному рендеру компонента.
getDerivedStateFromProps вызывается непосредственно перед вызовом метода render , как при начальном монтировании, так и при последующих обновлениях. Он должен вернуть объект для обновления состояния или null , чтобы ничего не обновлять.
Этот метод существует для редких случаев, когда состояние зависит от изменений в пропсах. Например, это подойдёт для реализации компонента <Transition> , который сравнивает свои предыдущие и следующие дочерние компоненты, чтобы решить, какой из них нужно анимировать.
Производное состояние приводит к сложному коду и делает ваши компоненты сложными для понимания. Убедитесь, что вы знакомы с простыми альтернативами:
Чтобы выполнить побочный эффект при изменении пропсов (например, сетевой запрос или анимацию) используйте componentDidUpdate .
Чтобы повторно вычислить данные при изменении пропсов, используйте функцию мемоизации.
Чтобы «сбросить» некоторое состояние при изменении пропсов, используйте управляемые компоненты или неуправляемые компоненты с ключом.
Этот метод не имеет доступа к экземпляру компонента. Чтобы использовать пропсы, состояние и методы класса в getDerivedStateFromProps() , их нужно вынести за пределы класса в виде чистых функций.
Если вы хотите повторно использовать код между getDerivedStateFromProps() и другими методами класса, извлеките чистые функции пропсов и состояния компонента и поместите их вне определения класса.
Обратите внимание, что этот метод запускается при каждом рендере, независимо от причины. Это отличается от метода UNSAFE_componentWillReceiveProps , который запускается только при повторном рендере родительского компонента, а не в результате вызова setState .
getSnapshotBeforeUpdate() вызывается прямо перед этапом «фиксирования» (например, перед добавлением в DOM). Он позволяет вашему компоненту брать некоторую информацию из DOM (например, положение прокрутки) перед её возможным изменением. Любое значение, возвращаемое этим методом жизненного цикла, будет передано как параметр componentDidUpdate() .
Это применяется редко, но может быть полезно в таких интерфейсах, как цепочка сообщений в чатах, в которых позиция прокрутки обрабатывается особым образом.
Значение снимка (или null ) должно быть возвращено.
В примерах выше важно получить значение свойства scrollHeight в getSnapshotBeforeUpdate из-за того, что могут возникать задержки между этапами жизненного цикла «рендер» (например, render ) и «фиксирование» (например, getSnapshotBeforeUpdate и componentDidUpdate ).
Предохранители – это React-компоненты, которые перехватывают JavaScript-ошибки в любом месте их дочернего дерева компонентов. Затем логируют эти ошибки и отображают запасной интерфейс вместо «поломанного» дерева компонентов. Предохранители отлавливают ошибки при рендере, в методах жизненного цикла и в конструкторах всего дерева под ними.
Классовый компонент становится предохранителем, если в нём используются методы жизненного цикла static getDerivedStateFromError() и (или) componentDidCatch() . Обновление состояния в этом методе жизненного цикла позволяет перехватить необработанную JavaScript-ошибку в дереве ниже и отобразить запасной интерфейс.
Используйте предохранители только для обработки неожиданных исключений, не используйте их для управления потоком исполнения в вашем приложении.
Примечание:
Предохранители перехватывают ошибки в компонентах ниже по дереву. Предохранители не могут поймать ошибку внутри себя.
Этот метод жизненного цикла вызывается после возникновения ошибки у компонента-потомка. Он получает ошибку в качестве параметра и возвращает значение для обновления состояния.
Примечание:
getDerivedStateFromError() вызывается во время этапа «рендера». Поэтому здесь запрещены любые побочные эффекты, но их можно использовать в componentDidCatch() .
Этот метод жизненного цикла вызывается после возникновения ошибки у компонента-потомка. Он получает два параметра:
- error — перехваченная ошибка
- info — объект с ключом componentStack , содержащий информацию о компоненте, в котором произошла ошибка.
componentDidCatch() вызывается во время этапа «фиксации», поэтому здесь можно использовать побочные эффекты. Метод можно использовать для логирования ошибок.
Обработка ошибок в методе componentDidCatch() отличается между React-сборками для продакшена и разработки.
В процессе разработки ошибки будут подниматься (всплывать) наверх до объекта window , поэтому любой вызов window.onerror или window.addEventListener(‘error’, callback) перехватит ошибки, которые были обработаны componentDidCatch() .
На продакшене, напротив, ошибки не всплывают, поэтому родительский обработчик ошибок перехватит только те ошибки, которые не были обработаны componentDidCatch() .
Примечание:
В случае ошибки вы можете рендерить запасной интерфейс с помощью componentDidCatch() , вызвав setState . Однако, этот способ скоро будет считаться устаревшим. Используйте static getDerivedStateFromError() для рендера резервного интерфейса.
Устаревшие методы жизненного цикла
Приведённые ниже методы жизненного цикла устарели. Их не рекомендуется использовать в новом коде, хотя они продолжают работать. Вы можете узнать больше о переходе с устаревших методов жизненного цикла в блоге.
Примечание:
Этот метод жизненного цикла раньше назывался componentWillMount . По этому названию он будет доступен до 17 версии. Чтобы автоматически обновить компоненты, используйте rename-unsafe-lifecycles .
UNSAFE_componentWillMount() вызывается непосредственно перед монтированием. Он вызывается перед render() , поэтому синхронный вызов setState() в этом методе не вызовет дополнительный рендер. Для инициализации состояния мы рекомендуем использовать constructor() .
Избегайте добавления каких-либо побочных эффектов или подписок в этом методе. Вместо этого используйте componentDidMount() .
Это единственный метод жизненного цикла, вызываемый при серверном рендеринге.
Примечание:
Этот метод жизненного цикла раньше назывался componentWillReceiveProps . По этому названию он будет доступен до 17 версии. Чтобы автоматически обновить компоненты, используйте rename-unsafe-lifecycles .
- Чтобы выполнить побочный эффект при изменении пропсов (например, сетевой запрос или анимацию) используйте componentDidUpdate .
- Чтобы повторно вычислить данные при изменении пропсов вместо componentWillReceiveProps используйте функцию мемоизации.
- Чтобы «сбросить» некоторое состояние при изменении пропсов вместо componentWillReceiveProps используйте управляемые компоненты или неуправляемые компоненты с ключом.
UNSAFE_componentWillReceiveProps() вызывается до того, как смонтированный компонент получит новые пропсы. Чтобы обновить состояние в ответ на изменение пропсов (например, для его сброса), можно сравнить this.props с nextProps и обновить состояние в этом методе с помощью this.setState() .
Обратите внимание, если родительский компонент заставляет ваш компонент повторно рендериться, метод будет вызываться, даже если пропсы не изменились. Убедитесь, что сравниваете текущие и следующие значения, если вы хотите обрабатывать изменения.
Во время монтирования React не вызывает UNSAFE_componentWillReceiveProps() с начальными значениями пропсов. Этот метод вызывается, если некоторые пропсы компонента могут обновиться. Вызов this.setState() обычно не вызывает UNSAFE_componentWillReceiveProps() .
Примечание:
Этот метод жизненного цикла раньше назывался componentWillUpdate . По этому названию он будет доступен до 17 версии. Чтобы автоматически обновить компоненты, используйте rename-unsafe-lifecycles .
UNSAFE_componentWillUpdate() вызывается непосредственно перед рендером при получении новых пропсов или состояния. В этом методе можно выполнить некоторую подготовку перед обновлением. Этот метод не вызывается при первом рендере.
Внутри этого метода нельзя вызвать this.setState() , а также делать какие-либо действия, которые влияют на обновление компонента перед возвратом UNSAFE_componentWillUpdate() (например, отправка действия Redux).
Обычно этот метод можно заменить на componentDidUpdate() . Вы можете использовать getSnapshotBeforeUpdate() для работы с DOM (например, запоминать положение прокрутки страницы).
Примечание:
UNSAFE_componentWillUpdate() не вызывается, если shouldComponentUpdate() возвращает false .
Другие методы API
В отличие от методов жизненного цикла, представленных выше (React вызывает их сам), методы, приведённые ниже, можно вызывать из компонентов.
Их всего два: setState() и forceUpdate() .
setState() добавляет в очередь изменения в состоянии компонента. Также он указывает React, что компонент и его дочерние элементы должны быть повторно отрендерены с обновлённым состоянием. Этот метод используется для обновления интерфейса в ответ на обработчики событий и ответы сервера.
Думайте о setState() , как о запросе, а не как о команде немедленного обновления компонента. Для увеличения производительности React может задержать его выполнение, а затем обновить несколько компонентов за один проход. React не гарантирует моментальное применение изменений в состоянии.
Метод setState() не всегда обновляет компонент сразу. Он может группировать или откладывать обновление до следующего раза. Это делает чтение this.state сразу после вызова setState() потенциальной ловушкой. Вместо этого используйте componentDidUpdate() или колбэк setState() ( setState(updater, callback) ), каждый из которых гарантированно вызывается после того как было применено обновление. Если вам нужно обновить состояние на основе предыдущего, используйте аргумент updater , описанный ниже.
setState() всегда приводит к повторному рендеру, если только shouldComponentUpdate() не возвращает false . Если используются мутабельные объекты, и условие рендеринга не может быть реализовано в shouldComponentUpdate() , вызывайте setState() только при разнице следующего и предыдущего состояния. Это предотвратит ненужные повторные рендеры.
Первым аргументом передаётся функция updater , которая имеет следующий вид:
state – ссылка на состояние компонента при изменении. Объект состояния не должен мутировать. Изменения должны проявляться в виде нового объекта на основе входных данных из state и props . Предположим, что мы хотели бы увеличить значение состояния с помощью props.step :
Как state , так и props , полученные функцией обновления, гарантированно будут обновлены. Результат функции поверхностно объединяется с state .
Второй параметр в setState() — необязательный колбэк, вызываемый после выполнения setState и повторного рендера компонента. Вместо этого в большинстве случаев для такой логики мы рекомендуем использовать componentDidUpdate() .
В качестве первого аргумента setState() , вместо функции, вы можете передать объект:
В нём образуется новое состояние после поверхностного объединения с stateChange . Например, установим количество товаров в корзине:
Эта форма записи setState() также асинхронна, и несколько вызовов в течение одного цикла могут быть объединены вместе. Например, вам нужно увеличить количество элементов несколько раз в одном цикле. Результат этого можно представить так:
Последующие вызовы будут переопределять значения из предыдущих вызовов того же цикла. Из-за этого количество увеличится только один раз. В случае, если следующее состояние зависит от текущего, мы рекомендуем использовать форму функции обновления:
Для более подробной информации смотрите:
По умолчанию при изменении состояния компонента или пропсов, происходит повторный рендер. Если ваш метод render() зависит от некоторых других данных, вы можете указать React необходимость в повторном рендере, вызвав forceUpdate() .
Вызов forceUpdate() приведёт к выполнению метода render() в компоненте, пропуская shouldComponentUpdate() . Это вызовет обычные методы жизненного цикла для дочерних компонентов, включая shouldComponentUpdate() каждого дочернего компонента. React по-прежнему будет обновлять DOM только в случае изменения разметки.
Чаще всего, forceUpdate() не используется. Вместо этого используются в render() данные из this.props и this.state .
defaultProps можно определить как свойство самого класса компонента, которое позволяет установить пропсы класса по умолчанию. Это используется для неопределённых ( undefined ) пропсов, но не для пропсов со значением null . Например:
Если props.color не передаётся, по умолчанию установится ‘синий’ :
Если props.color имеет значение null , оно останется null :
Строка displayName используется в сообщениях для отладки. Обычно вам не нужно её явно указывать. По умолчанию используется имя функции или класса, указанное при определении компонента. Если вам нужно установить его явно, например, для отладки или создания компонента высшего порядка, посмотрите раздел Обёртка отображаемого имени для простой отладки.
this.props содержит свойства, которые были определены тем, кто вызывает этот компонент. Подробнее об этом можно узнать в разделе Компоненты и пропсы
Существует специальный проп this.props.children , который обычно определяется дочерними тегами в JSX-выражении, а не в самом теге.
Состояние содержит данные, специфичные для этого компонента. Они могут измениться со временем. Состояние определяется пользователем и должно быть простым объектом JavaScript.
Вам не нужно вставлять в состояние значение, если оно не используется для рендера или потока данных (например, идентификатор таймера). Такие значения можно определить как поля экземпляра компонента.
Дополнительную информацию можно найти в разделе Состояние и жизненный цикл.
Force update the React component to re-render
In this tutorial, we are going to learn about how to force update the react class-based components and also functional components.
React generally re-renders the component whenever the component state or props are changed and we see the updated UI.
Forcing component to re-render
React has a forceUpdate() method by using that we can force the react component to re-render.
Let’s see an example.
Note: By calling forceUpdate() method react skips the shouldComponentUpdate() .
The second way to re-render a react component is by calling a setState() with the same state or empty state.
In the above code, we are calling this.setState(<>) method with an empty object, so react thinks that there is something changed in the component state and re-render the component with new UI.
React hooks force a component to re-render
In the react hooks, we don’t have a forceUpdate() method to re-render the component but we can do it by using a useState() hook.