Компонент углубленного анализа исходного кодаWillXXX, почему НЕБЕЗОПАСНО

React.js
Компонент углубленного анализа исходного кодаWillXXX, почему НЕБЕЗОПАСНО

отv16.3.0Начните следующие три крючка жизненного цикла, отмеченные какUNSAFE.

  • componentWillMount

  • componentWillRecieveProps

  • componentWillUpdate

Этому есть две причины:

  • Эти три хука часто используются неправильно, и теперь появляются лучшие альтернативы (здесь недавно добавленныйgetDerivedStateFromPropsа такжеgetSnapshotBeforeUpdate).

  • ReactотLegacyСхема перенесена вConcurrentПосле мода поведение этих хуков не будет таким, как раньше.

Эта статья начнется сReactПроанализируйте эти два момента с точки зрения исходного кода.

В то же время благодаря изучению данной статьи вы сможете освоитьReact异步状态更新机制принцип.

неправильно использованный крючок

Давайте сначала обсудим первый пункт, здесь мы используемcomponentWillRecievePropsПример.

мы частоcomponentWillRecievePropsВнутренняя обработкаpropsвлияние изменений. Некоторые ученики думают, что этот крючокpropsЗапускается после изменения.

Действительно? Давайте посмотрим на исходный код.

Этот код изupdateClassInstanceметод:

if (
  unresolvedOldProps !== unresolvedNewProps ||
  oldContext !== nextContext
) {
  callComponentWillReceiveProps(
    workInProgress,
    instance,
    newProps,
    nextContext,
  );
}

ты можешь начатьздесьпосмотреть этот источник

вcallComponentWillReceivePropsметод вызоветcomponentWillRecieveProps.

Видно, что ключом к тому, стоит ли звонить, является сравнениеunresolvedOldPropsа такжеunresolvedNewPropsконгруэнтны, иcontextизменять.

вunresolvedOldPropsкогда компонент последний раз обновлялсяprops,а такжеunresolvedNewPropsотClassComponentпередачаthis.renderвернутьJSXсерединаpropsпараметр.

увидеть их引用отличается. поэтому они全等比较дляfalse.

По этой причине,Каждое обновление родительского компонента вызывает обновление текущего компонента.componentWillRecieveProps.

Подумайте, если вы когда-нибудь злоупотребляли им?

миграция схемы

Рассмотрим вторую причину:

ReactотLegacyСхема перенесена вConcurrentПосле мода поведение этих хуков не будет таким, как раньше.

Давайте сначала разберемся, что такое шаблон? В чем разница между разными режимами?

От наследия к параллельному

отReact15обновитесь доReact16После этого исходный код сильно меняется, скажемReactРефакторинг может быть более подходящим.

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

Чтобы разработчики могли плавно перейти со старой версии на новую,ReactВведено три режима:

  • legacy模式-- пройти черезReactDOM.renderСозданное приложение включит этот режим. это текущийReactспособ использования. Этот режим может не поддерживать некоторые новые функции.
  • blocking模式-- пройти черезReactDOM.createBlockingRootСозданное приложение включит этот режим. открытая секцияconcurrentфункции схемы, перенесенные вconcurrentПервый шаг узора.
  • concurrent模式-- пройти черезReactDOM.createRootСозданное приложение включит этот режим. Перспективная модель развития.

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

concurrent模式по сравнению с тем, что мы сейчас используемlegacy模式Основное отличиеПреобразовать механизм синхронного обновления в асинхронное прерываемое обновление..

Далее мы обсудимReactКак добиться异步更新, и почему异步更新поведение хука в случае и同步更新разные.

Обновление синхронизации

мы можем использовать代码版本控制аналогия更新机制.

В отсутствие代码版本控制Раньше мы постепенно наращивали функциональность в нашем коде. Кажется, все в порядке, пока мы не столкнемся с серьезной онлайн-ошибкой (красный узел).

Чтобы исправить эту ошибку, нам нужно сначала закоммитить предыдущий код.

существуетReact, все проходятReactDOM.renderВсе приложения создали состояние обновления одинаковым образом.

то есть все更新синхронное исполнение, нет优先级концепт, новый高优更新(красные узлы) также необходимо ранжировать в других更新Выполнить позже.

Асинхронное обновление

когда есть代码版本控制, когда возникает срочная онлайн-ошибка, которую необходимо исправить, мы временно сохраняем модификацию текущей ветки, вmaster分支Исправьте ошибки и срочно запустите.

Пройдено после выхода исправления ошибкиgit rebaseкоманда и开发分支соединять.开发分支Продолжается разработка версии с исправленными ошибками.

существуетReactв, черезReactDOM.createBlockingRootа такжеReactDOM.createRootСозданное приложение будет обновлять состояние асинхронно, пока срок действия задачи не истек.

高优更新(красный узел) прерывание в процессе低优更新(синий узел), сначала завершите процесс рендеринга.

обращаться高优更新после завершения,低优更新на основе高优更新из部分или完整Результаты снова обновляются.

Углубитесь в исходный код

существуетReactВ исходном коде каждый раз, когда вы инициируете更新создастUpdateобъект, кратный одному и тому же компонентуUpdate(A -> B -> C, как показано выше) начнется с链表хранится в видеupdateQueueсередина.

Познакомьтесь с ними первыми数据结构.

UpdateЕсть много областей, в настоящее время мы сосредоточены на следующих трех областях:

const update: Update<*> = {
  // ...省略当前不需要关注的字段
  lane,
  payload: null,
  next: null
};

UpdateЗависит отcreateUpdateвозвращает метод, вы можете получить его изздесьВидетьcreateUpdateисходный код

  • полоса: представляет приоритет. то есть на картинке红色узел с蓝色Разница узлов.
  • полезная нагрузка: обновить смонтированные данные. дляthis.setStateсозданный更新,payloadдляthis.setStateпараметры.
  • следующий: с другимUpdateСвязано для формирования связанного списка.

updateQueueСтруктура выглядит следующим образом:

const queue: UpdateQueue<State> = {
    baseState: fiber.memoizedState,
    firstBaseUpdate: null,
    lastBaseUpdate: null,
    shared: {
      pending: null,
    },
    // 其他参数省略...
};

UpdateQueueЗависит отinitializeUpdateQueueвозвращает метод, вы можете получить его изздесьВидетьinitializeUpdateQueueисходный код

  • baseState:更新на основании чегоstateНачинать. На фото выше版本控制В примере ошибка высокого качества исправлена ​​​​и отправлена ​​​​послеmaster,разноеcommitна основеmasterФилиал продолжает развиваться. здесьmasterфилиалbaseState.
  • firstBaseUpdateа такжеlastBaseUpdate:更新на основании чегоUpdateначать сfirstBaseUpdateначатьlastBaseUpdateЗавершите формирование связанного списка. ЭтиUpdateбыл в последний раз更新из-за优先级Недостаточно, чтобы осталось, как показано на картинкеA B C.
  • shared.pending: одно или несколько из этого обновленияUpdateсформированный связанный список.

вbaseUpdate + shared.pendingбудет реализовано как это обновлениеUpdate.

пример

понял数据结构, то мы моделируем один раз异步中断更新, чтобы раскрыть секреты, раскрытые в этой статье -componentWillXXXЗачемUNSAFE.

в компонентеupdateQueueЕсть четыреUpdate字母представлятьUpdateписьма для обновления,数字представлятьUpdateприоритет, тем меньше число优先级выше.

baseState = '';

A1 - B2 - C1 - D2

При рендеринге в первый раз优先级1.B DНедостаточный приоритет для пропуска.

чтобы убедиться, что更新непрерывность первого пропущенаUpdate(B) и все последующиеUpdateбудет отображаться как второй разbaseUpdate, независимо от их优先级высокие и низкие, вотB C D.

baseState: ''
Updates: [A1, C1]
Result state: 'AC'

Затем второй рендер,优先级2.

из-заBпропускается при первом рендере, поэтому после егоCПолученные результаты рендеринга не будут отражены во втором рендеринге.baseStateсередина. такbaseStateдляAвместо последнего рендераResult state AC. Это также для обеспечения更新преемственности.

baseState: 'A'          
Updates: [B2, C1, D2]  
Result state: 'ABCD'

мы обнаруживаем,CПоявляется в обоих рендерах одновременноUpdates, он представляет状态будет обновлен дважды.

Если есть такой код:

componentWillReceiveProps(nextProps) {
    if (!this.props.includes('C') && nextProps.includes('C')) {
        // ...do something
    }
}

вероятно, будет вызван дважды, что то же самое, что и同步更新изReactНестабильная производительность!

По вышеуказанным причинам,componentWillXXXотмечен какUNSAFE.

Суммировать

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

Если вы хотите узнать большеReactИсходный код, я рекомендую его вам здесь开源,严谨,易懂Электронная книга React Source -Демистификация технологии React