В эпоху React16, какую позу мне следует использовать для написания React?

React.js
В эпоху React16, какую позу мне следует использовать для написания React?

Функциональные точки после React16 последовательно добавляются итеративно в нескольких версиях.Объяснение этой статьи основано на16.6.0версия Цель этой статьи - представить новые или измененные места в версии после React16, поэтому для функций версии до React16 эта статья расценивается как полное понимание вами, поэтому я не буду вдаваться в подробности.

Обзор обновлений

Обзор обновлений React v16.0 ~ React v16.6 (задействованы только некоторые распространенные API):

  • React v16.0
  1. renderПоддерживает возврат массивов и строк
  2. Поддержка пользовательских свойств DOM
  3. Уменьшить размер файла
  • React v16.3
  1. createContext
  2. createRef
  3. Обновления функций жизненного цикла
  • React v16.4

возобновитьgetDerivedStateFromProps

  • React v16.6
  1. memo
  2. lazy
  3. Suspense
  4. static contextType
  5. static getDerivedStateFromError
  • Реагировать v16.7 (~ 1 кв. 2019 г.)

Hooks

Далее мы объясним точки обновления с большим влиянием и более высокой частотой использования один за другим.

PureComponent для чистых функций

Мы знаем, что оптимизация производительности компонентов React,shouldComponentUpdateФункции важны, поэтому ReactReact.Componentдобавлено на основанииReact.PureComponent, но для написания чистой функции неклассовых классов такую ​​удобную обработку добавить нельзя. Для этой проблемы React16.6 добавилReact.memoЭта компонента высокого порядка

Общее использование:

const C = React.memo(props => {
  // xxx
})

React.memoРеализация похожа наReact.PureComponent, поэтому он внутренне выполняет поверхностное сравнение объектов.React.memoПозволяет настроить метод сравнения следующим образом:

// 函数的返回值为 true 时则更新组件,反之则不更新
const equalMethod = (prevProps, nextProps): boolean => {
  // 定义你的比较逻辑
}
const C = React.memo(props => {
  // xxx
}, equalMethod)

Как выглядит новая функция жизненного цикла

Жизненный цикл React делится на три этапа: монтирование, обновление и выгрузка.После React16 есть еще одно исключение.Давайте посмотрим.

[Обновлены картинки, отдельное спасибо @wuzhengyan2015 за исправление]

устанавливать

Порядок выполнения жизненного цикла

  1. constructor
  2. static getDerivedStateFromProps
  3. render
  4. componentDidMount

renderа такжеcomponentDidMountНикаких изменений по сравнению с тем, что было до React16. Для процесса монтажа давайте сосредоточимся наconstructor,componentWillMountа такжеstatic getDerivedStateFromProps.

constructor

  1. инициализировать состояние
    Примечание: следует избегатьpropsДатьstateзадание, чтобыstateМожно упомянуть инициализациюconstructorвнешнее лечение
constructor(props) {
  super(props);
  this.state = {
    x: 1,
    // y: props.y, // 避免这样做,后面我们会讲应该怎样处理
  }
}
  1. связать это с методом
constructor(props) {
  super(props);
  this.handleClick = this.handleClick.bind(this);
}

Тем не менее, две вышеуказанные вещи ставятсяconstructorВнешняя обработка будет проще, а именно:

class C extends React.Component {
  state = {
    x: 1
  }
  handleClick = (e) => {
    // xxx
  }
}

Поэтому React16 будет использоваться позжеconstructorсцены будут уменьшены.

componentWillMount

можно увидеть,componentWillMountЕго "убрали" в React16 (это на самом деле проблематично, т.к. React на самом деле не удаляет функцию жизненного цикла, а лишь предупреждает разработчиков о том, что эта функция будет устаревать в будущих версиях), тогда возникает проблема Теперь, что нужно сделать в этой жизненный цикл, где это должно быть сделано сейчас?

Сначала задайте себе вопрос, что есть в этом жизненном цикле? Ответ заключается в том, что большую часть времени нужно выполнять запросы AJAX, а затем выполнятьsetStateПеререндерить.

Однако вcomponentWillMountДелать здесь AJAX-запросы действительно неразумно, потому что для изоморфных проектовcomponentWillMountбудет называться.

Кто-то еще будет инициализировать здесьstatestateДля инициализации обратитесь к разделу выше.

В итоге,componentWillMountНа самом деле, это не играет никакой роли: если ваша спецификация кода будет удалена, это никак не повлияет на текущий проект.

static getDerivedStateFromProps

Как мы упоминали выше, нам следует избегать использованияpropsДатьstateПрисваивание, но мы делали это до React 16. Теперь, если мы не разрешаем эту операцию, где мы должны иметь дело с этой логикой? Ответ, данный React16,static getDerivedStateFromProps.
Когда компонент смонтирован, статический метод будетrenderперед выполнением; при обновлении компонента статический метод будет выполняться вshouldComponentUpdateперед казнью.

class C extends React.Component {
  state = {
    y: 0
  }
  static getDerivedStateFromProps(props, state): State {
    if(props.y !== state.y) {
      return {
        y: props.y
      };
    }
  }
}

getDerivedStateFromPropsВозвращаемое значение будет такимsetStateПараметр, если он возвращает null, состояние не будет обновлено, и значение, отличное от object или null, не может быть возвращено, иначе будет выдано предупреждение.

getDerivedStateFromPropsЭто статический метод и не может получить экземплярthis, поэтому разработчики должны проектировать эту функцию как чистую функцию.

Итак, вы нашлиcomponentWillReceivePropsЭто бесполезно? Да, React16 тоже "удалил" его (это на самом деле проблематично, т.к. react на самом деле не удаляет функцию жизненного цикла, а лишь предупреждает разработчиков, что эта функция будет устаревать в будущих версиях, рекомендуется использовать более качественнуюgetSnapshotBeforeUpdateилиgetDerivedStateFromProps)

возобновить

Порядок выполнения функций жизненного цикла

  1. static getDerivedStateFromProps
  2. shouldComponentUpdate
  3. render
  4. getSnapshotBeforeUpdate
  5. componentDidUpdate

static getDerivedStateFromPropsОн был представлен ранее, и несколько других функций жизненного цикла в основном такие же, как и до React16, так что вот основное введение.getSnapshotBeforeUpdate.

getSnapshotBeforeUpdate

Вызывается до того, как React обновит DOM, на данный моментstateобновлено; возвращаемое значение какcomponentDidUpdateТретий параметр; обычно используется для полученияrenderпредыдущие данные DOM

грамматика:

class C extends React.Component {
  getSnapshotBeforeUpdate (prevProps, prevState): Snapshot {
    
  }
  componentDidUpdate(prevProps, prevState, snapshot) {
    // snapshot 是从 getSnapshotBeforeUpdate 的返回值,默认是 null
  }
}

getSnapshotBeforeUpdateСценарий использования обычно заключается в получении положения полосы прокрутки до обновления компонента.

удалить

componentWillUnmount

Никаких изменений по сравнению с предыдущим.

аномальный

componentDidCatchЭта функция является новой в React16 и используется для перехвата исключений в дереве компонентов, еслиrender()Если функция выдает ошибку, функция будет запущена. может следоватьtry catchчтобы понять и использовать, где могут возникнуть ошибки, используйте упакованные включаетcomponentDidCatchКомпоненты жизненного цикла оборачивают компоненты, которые могут пойти не так.

class PotentialError extends React.Component {
  state = {
    error: false,
  }
  componentDidCatch(error, info) {
    console.error(info);
    this.setState({
      error
    });
  }
  render() {
    if (this.state.error) {
      return <h1>出错了,请打卡控制台查看详细错误!</h1>;
    }
    return this.props.children;   
  } 
}

Такие как:

const Demo = () => (
  <PotentialError>
    <div>{{a: 1}}</div>
  </PotentialError>
)

так,DemoДаже если компонент напрямую использует объект как подкомпонент, он не сообщит об ошибке, т.к.PotentialErrorполучено.

Полная демонстрация нового жизненного цикла

Посмотрите, как это выглядит в новой одежде нового жизненного цикла

import React from 'react'

export default class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    // 初始化state方式(1)
    this.state = {

    }
  }
    
  static defaultProps = {

  }

  // 初始化state方式(2)
  state = {

  }
  static getDerivedStateFromProps(props, state) {
    return state
  }
  componentDidCatch(error, info) {

  }
  render() {

  }
  componentDidMount() {

  }
  shouldComponentUpdate(nextProps, nextState) {
    
  }
  getSnapshotBeforeUpdate(prevProps, prevState) {

  }
  componentDidUpdate(prevProps, prevState, snapshot) {

  }
  componentWillUnmount() {

  }

}

Suspense

Hooks

time slicing

【Продолжение следует】