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

sCU спешит на помощь!

Решение состоит в том, чтобы использовать методы жизненного цикла React, наиболее важным из которых с точки зрения производительности является shouldComponentUpdate (sCU). Этот метод принимает аргументы nextProps и nextState, которые можно использовать для сравнения с this.props и this.state, чтобы определить, было ли изменение, и требует ли это изменение обновления компонента. sCU всегда должен возвращать логическое значение:

shouldComponentUpdate = (nextProps, nextState) => {
  return (true|false)
}

За кулисами React реализует sCU для каждого компонента, который всегда возвращает true. Разработчик должен переопределить этот метод и определить условия для обновления (повторного рендеринга). Полезный метод обеспечения строгих правил рендеринга - изначально написать компонент с помощью sCU return false. Таким образом мы говорим компоненту не выполнять повторную визуализацию ни при каких обстоятельствах. В приведенном ниже примере у нас есть простой компонент, который отображает кнопку.

class MyComponent extends React.Component {
  shouldComponentUpdate = (nextProps, nextState) => false
  render() {
    <Button label='Click me' />
  }
}

Долгая игра…

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

class MyComponent extends React.Component {
  state = {
    loading: false
  }
  loadData = () => {
    this.setState({ loading: true })
    api.loadData.then(() => {
      this.setState({ loading: false })
    })
    .catch(() {
      this.setState({ loading: false })
    })
  }
  shouldComponentUpdate = (nextProps, nextState) => {
    return nextState.loading !== this.state.loading
  }
  render() {
    <div>
      <Button label='Click me' />
      <Loader display={this.state.loading} />
    </div>
  }
}

Теперь мы добавили в sCU условие, обеспечивающее выполнение строгих правил обновления; если это условие не выполняется, компонент не будет повторно визуализироваться ни при каких обстоятельствах после начальной загрузки. В приложении Button, вероятно, будет содержаться в родительском элементе. Если и когда этот родительский объект выполняет повторный рендеринг, нам, скорее всего, не понадобится кнопка для повторного рендеринга вместе с ним. Мы получили прирост производительности!

Причина для немедленного добавления sCU двоякая. Во-первых, у нас есть заполнитель, позволяющий другим разработчикам в нашей команде добавлять условия по мере необходимости, тем самым «разблокируя» правила обновления компонента. Фактически, они будут вынуждены сделать это, если захотят, чтобы компонент повторно отображался после добавления новых свойств или состояния. Во-вторых, мы подошли к созданию наших компонентов, ориентируясь на «производительность прежде всего». За время разработки компонента мы позаботились о том, чтобы каждая добавленная сложность не ухудшала взаимодействие с пользователем. Альтернативой является ожидание, пока компонент не станет сложным, и в этот момент мы часто вынуждены решать проблемы с производительностью. Выяснить условия повторного рендеринга намного сложнее, если вам нужно делать все сразу, а не постепенно с течением времени.

TL;DR

При разработке нового компонента помните об этих трех простых шагах:

  1. Всегда создавайте метод жизненного цикла sCU.
  2. Примите мышление «прежде всего производительность» и сделайте так, чтобы sCU возвращал ложные данные во всех случаях.
  3. Когда компонент получает новые свойства и / или состояние, «разблокируйте» повторный рендеринг, добавив логику в sCU.

PS. Присоединяйтесь к нам в Посольстве, набираем!