Что такое управление потоком в режиме строгого соблюдения React?

Вопрос или проблема

Какой будет результат выполнения следующего компонента в режиме строгой проверки React?

import { useEffect } from "react";

export default function Learn() {
    let x = 1;
    console.log("снаружи ", x)
    useEffect(() => {
        console.log(x);
        x = 2;

        return () => console.log("разрушение", x)
    }, []);
    console.log("конец функции ", x)
    return (
        <>
            <p>значение = {x}</p>
        </>
    );
}

Я запустил это на своем компьютере и получил

снаружи  1
конец функции  1
снаружи  1
конец функции  1
1
разрушение 2
2

Но я не могу понять, почему. По моему разумению, это должно было быть

снаружи 1
конец функции 1
1
разрушение 2
снаружи 1
конец функции 1
1

Что я предполагал (неправильно), так это то, что режим строгой проверки React будет:

  1. Начнет добавлять компонент в виртуальный DOM.
  2. Как только монтирование завершено, он вызовет хук useState.
  3. повторяет (1) и (2) снова.

Но этого здесь не происходит. Так что же здесь происходит?

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

Ожидаемый порядок выполнения
Режим строгой проверки React преднамеренно вызывает компоненты дважды во время разработки, чтобы помочь выявить проблемы с побочными эффектами. Давайте рассмотрим каждый шаг:

Первоначальный рендер – Первый вызов

let x = 1;: Инициализирует x равным 1.
console.log("снаружи ", x);: Логирует снаружи 1.
console.log("конец функции ", x);: Логирует конец функции 1.

Компонент рендерится со значением = 1.
useEffect выполняется после завершения этого рендера.
Выполнение эффекта (Первый вызов)

console.log(x);: Логирует 1.
x = 2;: Меняет x на 2.
return () => console.log("разрушение", x);: Настраивает функцию очистки для логирования 

разрушения и текущего значения x, когда компонент размонтируется или перерендерится.
Размонтирование (Первый вызов)

Функция очистки выполняется как часть поведения режима строгой проверки, логируя разрушение 2.
Повторное монтирование (Второй вызов)

React повторно монтирует компонент с нуля, чтобы смоделировать новое начало:

let x = 1;: x сбрасывается на 1.
console.log("снаружи ", x);: Логирует снаружи 1.
console.log("конец функции ", x);: Логирует конец функции 1.
Компонент снова рендерится со значением = 1.

Выполнение эффекта (Второй вызов)

console.log(x);: Логирует 1.
x = 2;: Снова меняет x на 2.
return () => console.log("разрушение", x);: Настраивает новую функцию очистки для логирования 

разрушения и текущего значения x, когда компонент размонтируется или перерендерится.

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

Ответ или решение

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

Понимание строгого режима React

Строгий режим (Strict Mode) в React — это инструмент для выявления потенциальных проблем в приложении на этапе разработки. Он включает в себя несколько механизмов проверки, один из которых — двойной вызов функций жизненного цикла и эффектов. Это поведение направлено на то, чтобы помочь разработчикам обнаружить некорректно обрабатываемые побочные эффекты, улучшая предсказуемость и стабильность компонентов.

Этапы выполнения компонента Learn

Первый вызов (первое отображение компонента)

  1. Инициализация:

    • let x = 1; — переменная x инициализируется значением 1.
    • console.log("outside ", x); — выводит: outside 1.
  2. Экспорт компонента:

    • console.log("end of fn ", x); — выводит: end of fn 1.
  3. Рендеринг:

    • Компонент отображает: <p>value = {x}</p>, что дает 1.

Запуск эффекта (первый вызов)

После завершения рендеринга срабатывает эффект useEffect:

  1. console.log(x); — выводит: 1.
  2. x = 2; — значение x изменяется на 2.
  3. return () => console.log("destruct", x); — создается функция очистки, которая будет вызвана при размонтировании компонента или повторном рендеринге.

Размонтирование (первый вызов)

При размонтировании компонента срабатывает функция очистки:

  • console.log("destruct", x); — выводит: destruct 2.

Второй вызов (второе отображение компонента)

React повторно монтирует компонент для имитации нового цикла рендеринга:

  1. Сброс состояния:

    • let x = 1; — переменная x снова инициализируется значением 1.
    • console.log("outside ", x); — выводит: outside 1.
    • console.log("end of fn ", x); — выводит: end of fn 1.
  2. Рендеринг повторно:

    • Компонент снова отображает: 1.

Запуск эффекта (второй вызов)

Теперь влияние эффекта видимо вновь:

  1. console.log(x); — выводит: 1.
  2. x = 2; — снова изменяется на 2.
  3. Создается новая функция очистки, аналогичная предыдущей.

Пояснение почему вывод именно такой

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

Заключение

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

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

Оцените материал
Добавить комментарий

Капча загружается...