Реагирует на функциональный компонент с контролируемым отображением на основе значений состояния / реквизита

#reactjs #react-hooks

#reactjs #реагирующие хуки

Вопрос:

Одним из преимуществ возможности использования shouldComponentUpdate в компоненте класса React является возможность управлять отображением на основе условия, а не просто изменением значений состояния / prop.

Какой предпочтительный способ выполнить эту оптимизацию с использованием react hooks в функциональном компоненте?

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

 class DrawerComponent extends React.Component {
  static propTypes = {
    children: PropTypes.any,
  }

  state = {
    isOpen: false,
  }

  // only re-render if the drawer is open or is about to be open.
  shouldComponentUpdate(nextProps, nextState) {
    return this.state.isOpen || nextState.isOpen;
  }

  toggleDrawer = () => {
    this.setState({isOpen: !this.state.isOpen});
  };

  render() {
    return (
      <>           
        <div onClick={this.toggleDrawer}>
          Drawer Title
        </div>
        <div>
          {this.state.isOpen ? this.props.children : null}
        </div>
      </>
    )
  }
}
  

Аналог функционального компонента (без оптимизации):

 function DrawerComponent({ children }) {
  const [isOpen, setIsOpen] = useState(false);

  function toggle() {
    setIsOpen(!isOpen);
  } 

  return (
    <>
      <div onClick={toggle}>
        Drawer Title
      </div>
      <div>{isOpen ? children : null}</div>
    </>
  );
}
  

Ответ №1:

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

Тем не менее, если вы действительно хотите реализовать эквивалентное поведение в функциональном компоненте, вы могли бы использовать React.memo и предоставить пользовательскую areEqual функцию: https://reactjs.org/docs/react-api.html#reactmemo.

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

1. Насколько я помню, учитывая ваш пример, вызов setIsOpen с одним и тем же значением дважды не вызовет повторного рендеринга. Значение должно пройти строгую проверку на равенство === .

2. Я думаю, вам понадобится useCallback для этого. Однако я не пытаюсь перехватить повторный рендеринг из setIsOpen , скорее, изменение дочерних элементов во время isOpen === false

3. Я собрал этот codesandbox вместе, чтобы продемонстрировать, что передача того же значения в setX не вызывает повторного отображения, даже с массивом, в котором есть новый элемент: codesandbox.io/s/0ypy38q9rw

4. @JamieKudla если бы у вас была веская причина, вы могли бы запомнить дерево элементов, которое вы возвращаете в своей функции, и вернуть предыдущее значение, если ящик закрыт. Тогда React не будет утруждать себя дифференцированием или иной обработкой выходных данных. В качестве альтернативы у вас может быть дочерний компонент, который получает оба children и isOpen в качестве реквизита и предотвращает рендеринг с React.memo , как описано. Однако в данном сценарии это действительно перебор.

5. @Joru Не относится конкретно к этому сценарию, просто любопытно, как можно обработать что-то подобное. Я думаю, что создание нового компонента, который получает значения состояния в качестве реквизита и обрабатывает через memo , — это ответ, который я ищу, спасибо!.