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

#javascript #reactjs #react-hooks

#javascript #reactjs #реагирующие перехваты

Вопрос:

Компоненты класса

В компонентах класса React нам говорят, что это setState всегда приводит к повторному рендерингу, независимо от того, действительно ли состояние изменилось на новое значение. По сути, компонент будет повторно рендериться, когда состояние обновится до того же значения, которое было раньше.

Документы (ссылка на setState API):

setState() всегда приведет к повторному рендерингу, если shouldComponentUpdate() не возвращает false .


Перехваты (функциональные компоненты)

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

Документы (ссылка на API useState):

Отказ от обновления состояния

Если вы обновите перехват состояния до того же значения, что и текущее состояние, React завершит работу без рендеринга дочерних элементов или запуска эффектов. (React использует Object.is алгоритм сравнения.)


Тесно связанные вопросы

  1. Правильно ли, что this.setState компоненты в классе всегда вызывают повторный рендеринг, даже когда новое state значение идентично предыдущему?
  2. Правильно ли, что в функциональных компонентах с помощью перехватов setState from useState вызывает повторный рендеринг, только если state значение отличается от предыдущего значения?
  3. Является ли настройка state с помощью this.setState внутри render метода компонента класса такой же, как настройка state внутри тела функции функционального компонента с помощью перехватов?
  4. Верно ли следующее?
    • В компоненте класса, если мы установим state в render методе, будет происходить бесконечный цикл. Это потому, что компоненту класса все равно, что новый state совпадает с предыдущим state . Он просто продолжает повторный рендеринг при каждом this.setState .
    • Однако в функциональном компоненте с перехватами настройка внутри тела функции (которая выполняется при повторном рендеринге аналогично state методу в render компонентах класса) не была бы проблемой, потому что функциональный компонент просто прекращает повторный рендеринг, когда видит, что он идентичен предыдущему state . …………………… state

Комментарии:

1. we are told that setState always causes a re-render я не уверен в этом. Если вы возвращаете null this.setState(() => null) , он ничего не рендерит повторно.

2. Что именно вы подразумеваете под вызовом 3? setState?

3. @estus Да, прояснил OP.

Ответ №1:

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

Если вы задаете допустимое значение, отличное от возвращаемого null в setState, повторный рендеринг всегда будет запускаться react в компоненте класса, если ваш компонент не является PureComponent или вы не реализуете shouldComponentUpdate

Правильно ли, что в функциональных компонентах с перехватами setState из useState вызывает повторный рендеринг, только если значение состояния отличается от предыдущего значения?

Для функционального компонента, использующего useState перехват, установщик, если он вызван с тем же состоянием, не запустит повторный рендеринг. Однако в редких случаях, если установщик вызывается немедленно, это приводит к двум рендерингам вместо одного

Устанавливает ли state с помощью this.setState внутри метода рендеринга компонента класса то же самое, что устанавливает state внутри тела функции функционального компонента с помощью перехватов?

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

В компоненте класса, если мы установим состояние в методе render, возникнет бесконечный цикл. Это происходит потому, что компоненту класса все равно, что новое состояние совпадает с предыдущим состоянием. Он просто продолжает повторный рендеринг для каждого this.setState.

Да, следовательно, рекомендуется не вызывать setState непосредственно при рендеринге

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

Не на 100% верно, поскольку вы можете инициировать обновление состояния, используя предыдущее значение, так что предыдущее и текущее значения не совпадают.Например

 setCount(count => count   1);
  

В таком случае ваш компонент все равно попадет в бесконечный цикл

Комментарии:

1. Если вы реализуете shouldComponentUpdate для возврата false, если состояние или реквизиты не изменились, то ваш компонент не будет повторно рендерить

2. @Magnus, да, опечатка с моей стороны. Обновлен ответ

3. Спасибо, глубоко признателен. Где вы находите всю эту информацию? В официальных документах очень мало информации о том, когда и почему происходят повторные рендеринги. Они действительно должны создать страницу по этой теме…

4. Я так или иначе тестировал вышеупомянутые сценарии с течением времени

5. @Magnus, да, ты прав. эффекты представляют собой дополнительную логику к функциональному компоненту, которого нет в render for class component

Ответ №2:

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

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

В этом примере из документации React функция будет выполнена только при props.source изменении.

 useEffect(
  () => {
    const subscription = props.source.subscribe();
    return () => {
      subscription.unsubscribe();
    };
  },
  [props.source],
);
  

Документы React: useEffect()