О новом жизненном цикле React v16.3

React.js

Измененная часть

наконец-то вышел react v16.3, самое большое изменение в том, что жизненный цикл удалил следующие три

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

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

  • static getDerivedStateFromProps
  • getSnapshotBeforeUpdate

Конечно, эта замена медленная, и старые три жизненных цикла можно без проблем использовать во всей 16-й версии, но стоит отметить, что старый жизненный цикл (небезопасный) не может появиться в компоненте одновременно с новый жизненный цикл. В противном случае будет сообщено об ошибке «Вы использовали небезопасное время жизни».

зачем менять

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

Но он терпеть не может, когда чиновник делает что-то сам по себе, React планирует запустить новый асинхронный рендеринг в версии 17, предлагая жизненный цикл, который можно прервать, а этап, который можно прервать, — это этап построения виртуального DOM перед фактическая модель DOM смонтирована, это три жизненных цикла, которые необходимо удалить.

После прерывания жизненного цикла предыдущий жизненный цикл будет запущен снова при следующем возобновлении, поэтому componentWillMount, componentWillReceiveProps и componentWillUpdate не могут гарантировать, что они будут обновлены только один раз при монтировании/получении реквизитов/изменении статуса, поэтому эти три метода помечены как небезопасные.

Два новых жизненных цикла

static getDerivedStateFromProps

  • Время срабатывания (исправление версии 16.4): каждый раз при рендеринге компонента, в том числе после сборки компонента (последнее выполнение перед рендерингом) и после получения каждого нового реквизита или состояния. В v16.3 обновление состояния компонента не запускает этот жизненный цикл.
  • Каждый раз, когда будут получены новые реквизиты, объект будет возвращен как новое состояние.Возврат нулевого значения означает, что состояние не нужно обновлять.
  • С помощью componentDidUpdate вы можете переопределить все случаи использования componentWillReceiveProps.
class Example extends React.Component {
  static getDerivedStateFromProps(nextProps, prevState) {
    // 没错,这是一个static
  }
}

getSnapshotBeforeUpdate

  • Время срабатывания: когда происходит обновление, после рендеринга, до рендеринга dom компонента.
  • Возвращает значение в качестве третьего параметра componentDidUpdate.
  • С помощью componentDidUpdate все случаи использования componentWillUpdate могут быть переопределены.
class Example extends React.Component {
  getSnapshotBeforeUpdate(prevProps, prevState) {
    // ...
  }
}

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

  1. Initializing state — Инициализирующее состояние

    • Просто инициализируйте состояние в конструкторе
  2. Request Data — Получение внешних данных

    • Запросить асинхронно загруженные данные в componentDidMount
    • Есть иллюзия, что данные, запрошенные в componentWillMount, можно получить в рендере, но на самом деле рендер вызывается почти сразу после willMount, и данные вообще нельзя вернуть, так же нужно рендерить "загрузку" пустых данных состояние, поэтому выборка данных в didMount почти не влияет.
  3. Добавление прослушивателей событий — Добавление прослушивателей событий (или подписок)

    • Добавить прослушиватель событий в componentDidMount
    • React может гарантировать только то, что компонентDidMount-componentWillUnmount появляется парами, а componentWillMount может быть прерван или вызван несколько раз, поэтому нет гарантии, что слушатели событий могут быть успешно размонтированы во время размонтирования, что может вызвать утечку памяти.
  4. Обновление состояния на основе реквизита — Обновление состояния на основе реквизита

    • Используйте getDerivedStateFromProps(nextProps, prevState) для обновления входящих реквизитов до состояния
    • Используемый вместо componentWillReceiveProps(nextProps, nextState), willReceiveProps часто используется неправильно, вызывая некоторые проблемы, поэтому этот метод будет объявлен устаревшим.
    • getDerivedStateFromProps — это статический метод, что означает, что this экземпляра нельзя получить, поэтому я хочу сравнить, были ли обновлены реквизиты до setState.Следующий метод использовать нельзя.
     if (this.props.currentRow !== nextProps.currentRow) {
     	...
     }
    

    Вместо этого напишите дополнительное состояние для записи предыдущего реквизита (`^')

    if (nextProps.currentRow !== prevState.lastRow) {
      return {
        ...
        lastRow: nextProps.currentRow,
      };
      // 不更新state
      return null
    }
    
    • Почему бы не дать параметр prevProps?Официальное объяснение - при первом вызове prevProps он нулевой, и о потреблении производительности надо судить для каждого обновления.Второе, если все к этому привыкли, react не будет записывать prevProps в будущем (Что), может сэкономить много памяти
  5. Триггерный запрос — Вызов внешних обратных вызовов

    • В жизненном цикле запрос срабатывает из-за изменения состояния, которое осуществляется в componentDidUpdate
    • Причины, по которым не в componentWillUpdate такие же, как указано выше 2
  6. Побочные эффекты при изменении реквизита — Побочные эффекты при изменении реквизита

    • Визуальные изменения, вызванные изменениями реквизита (побочные эффекты, такие как журнал, ga), обрабатываются в componentDidUpdate.
    // 在didUpdate中根据props更新的确很不适应
    // props变了也是可以触发update的
    componentDidUpdate(prevProps, prevState) {
    	if (this.props.isVisible !== prevProps.isVisible) {
    	  logVisibleChange(this.props.isVisible);
    	}
    }
    
    • componentWillUpdate, componentWillReceiveProps могут запускаться несколько раз в обновлении, поэтому этот побочный эффект, который, как ожидается, будет запущен только один раз, должен быть помещен в componentDidUpdate, который гарантированно будет запускаться только один раз.
  7. Re-request when props update — Извлечение внешних данных при изменении реквизита

    • Повторная выборка данных асинхронно при передаче новых реквизитов, getDerivedStateFromProps+ componentDidUpdate заменяет componentWillReceiveProps
    // old
      componentWillReceiveProps(nextProps) {
        if (nextProps.id !== this.props.id) {
        	this.setState({externalData: null});
          this._loadAsyncData(nextProps.id);
        }
      }
    
    // new
      static getDerivedStateFromProps(nextProps, prevState) {
        // Store prevId in state so we can compare when props change.
        if (nextProps.id !== prevState.prevId) {
          return {
            externalData: null,
            prevId: nextProps.id,
          };
        }
        // No state update necessary
        return null;
      }
      componentDidUpdate(prevProps, prevState) {
        if (this.state.externalData === null) {
          this._loadAsyncData(this.props.id);
        }
      }
    
  8. Запишите исходные свойства узла DOM перед обновлением — Чтение свойств DOM перед обновлением

    • Получите узел dom перед обновлением, getSnapshotBeforeUpdate(prevProps, prevState) вместо componentWillUpdate(nextProps, nextState)
    • getSnapshotBeforeUpdate после рендеринга, но до монтирования узла
    • componentDidUpdate(prevProps, prevState, snapshot) напрямую получает значение свойства dom, возвращаемое getSnapshotBeforeUpdate

Краткий обзор замены функций жизненного цикла

  static getDerivedStateFromProps(nextProps, prevState) {
    4. Updating state based on props
    7. Fetching external data when props change // Clear out previously-loaded data so we dont render stale stuff
  }
  constructor() {
	1. Initializing state
  }
  componentWillMount() {
  	// 1. Initializing state
  	// 2. Fetching external data
  	// 3. Adding event listeners (or subscriptions)
  }
  componentDidMount() {
	2. Fetching external data
	3. Adding event listeners (or subscriptions)
  }
  componentWillReceiveProps() {
  	// 4. Updating state based on props
  	// 6. Side effects on props change
  	// 7. Fetching external data when props change
  }
  shouldComponentUpdate() {
  }
  componentWillUpdate(nextProps, nextState) {
  	// 5. Invoking external callbacks
  	// 8. Reading DOM properties before an update
  	
  }
  render() {
  }
  getSnapshotBeforeUpdate(prevProps, prevState) {
	8. Reading DOM properties before an update
  }
  componentDidUpdate(prevProps, prevState, snapshot) {
	5. Invoking external callbacks
	6. Side effects on props change
  }
  
  componentWillUnmount() {
  }

наконец

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

Если вас интересуют более подробные сведения, вы можете перейти к официальной документации, https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html.

Если вас интересует асинхронный рендеринг или вас интересует младший брат Дэна, вы можете взглянуть на его небольшую демонстрацию на конференции по внешнему интерфейсу: https://reactjs.org/blog/2018/03/ 01/sneak-peek-beyond-react- 16.html