Прочитайте это перед использованием React 18…

React 18 был выпущен 29 марта 2022 года.

После прочтения статьи в блоге «Как перейти на React 18» я вынес для себя следующие основные моменты:

  1. Обновления API клиентского рендеринга, одно незначительное изменение, которое нужно применить в вашем главном файле index.tsx:
// Before
import { render } from 'react-dom';
const container = document.getElementById('app');
render(<App tab="home" />, container);

// After
import { createRoot } from 'react-dom/client';
const container = document.getElementById('app');
const root = createRoot(container); // createRoot(container!) if you use TypeScript
root.render(<App tab="home" />);
Вход в полноэкранный режим Выход из полноэкранного режима
  1. Обновления в определениях TypeScript. Теперь разработчики должны явно указывать дочерний реквизит при определении реквизитов, например:
interface MyButtonProps {
  color: string;
  children?: React.ReactNode;
}
Войти в полноэкранный режим Выйти из полноэкранного режима

В статье блога объясняются другие изменения и дополнения в React 18, однако большинству разработчиков React не потребуется ничего делать.

Это дало мне уверенность в том, что я сразу же перейду к обновлению своего приложения до React 18.

Обновление до 18

Сразу же я заметил некоторые странности в поведении приложения:

Перейдя в консоль, я увидел, что мой компонент «setup» useEffect с пустым массивом зависимостей срабатывает дважды.
Я был уверен, что не изменил код компонента, и не мог понять, почему я вижу двойной рендеринг моего компонента.

Catastrophe No GIF by Cultura — Find & Share on GIPHY

Найдите & поделитесь этим GIF от Cultura со всеми, кого вы знаете. GIPHY — это способ поиска, обмена, обнаружения и создания GIF.

giphy.com

Быстрый поиск в Google указал на то, что причиной является компонент <StrictMode />.

(временное) решение

Измените мой код следующим образом

import { StrictMode } from "react";
import * as ReactDOMClient from "react-dom/client";

import App from "./App";

const rootElement = document.getElementById("root");
const root = ReactDOMClient.createRoot(rootElement);

root.render(
  <StrictMode>
    <App />
  </StrictMode>
);
Войти в полноэкранный режим Выйти из полноэкранного режима

на

import * as ReactDOMClient from "react-dom/client";

import App from "./App";

const rootElement = document.getElementById("root");
const root = ReactDOMClient.createRoot(rootElement);

root.render(
    <App />
);
Войти в полноэкранный режим Выход из полноэкранного режима

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

Причина

В нижней части сообщения React 18 Upgrade Guide они объясняют:

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

* React mounts the component.
  * Layout effects are created.
  * Effects are created.

В режиме Strict Mode, начиная с React 18, каждый раз, когда компонент монтируется в процессе разработки, React будет имитировать немедленное размонтирование и повторное монтирование компонента:

* React mounts the component.
    * Layout effects are created.
    * Effect effects are created.
* React simulates effects being destroyed on a mounted component.
    * Layout effects are destroyed.
    * Effects are destroyed.
* React simulates effects being re-created on a mounted component.
    * Layout effects are created
    * Effect setup code runs

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

Правильное исправление

Добавление оператора возврата в useEffect для очистки эффекта при размонтировании.

import { useEffect, useState } from "react";

const intervalInMs = 100;
const minuteInMs = 1000;

export const React18SafeTimer = () => {
  const [timeInSeconds, setTime] = useState(0);
  const [updateTimerInterval, setUpdateTimerInterval] = useState(0);

  useEffect(() => {
    console.log("React 18 Timer Setup");
    const timerInterval = setInterval(
      () => setTime((t) => t + intervalInMs / minuteInMs),
      intervalInMs
    );
    setUpdateTimerInterval(timerInterval);
    // THE FIX: Add next line to properly clean up useEffect
    return () => clearInterval(timerInterval);
  }, []);

  const handleClearTimer = () => {
    clearInterval(updateTimerInterval);
  };

  return (
    <>
      <p>seconds since page load: {timeInSeconds.toFixed(1)}</p>
      <button onClick={handleClearTimer}>Stop Timer</button>
    </>
  );
};
Вход в полноэкранный режим Выход из полноэкранного режима

Более подробную информацию можно найти на странице Hooks API Reference.

Если у вас возникли проблемы после обновления до React 18, посмотрите на любой из следующих примеров, так как изменения StrictMode вокруг изменения размонтирования и повторного монтирования включают в себя:

  • componentDidMount
  • componentWillUnmount
  • useEffect
  • useLayoutEffect
  • useInsertionEffect .

Более подробную информацию смотрите на этой странице.

Почему я должен использовать StrictMode?

StrictMode — это инструмент (режим разработки) для выделения потенциальных проблем в приложении. Он не работает в производственной среде. Как и Fragment, StrictMode не отображает никакого видимого пользовательского интерфейса. Он активирует дополнительные проверки и предупреждения для своих потомков.

В настоящее время StrictMode помогает:

  • Выявление компонентов с небезопасным жизненным циклом
  • Предупреждение об использовании устаревшего API string ref
  • Предупреждение об использовании устаревшего findDOMNode
  • Обнаружение неожиданных побочных эффектов
  • Обнаружение устаревшего API контекста
  • Обеспечение повторного использования состояния
  • Дополнительная функциональность будет добавлена в будущих выпусках React.

Почему React внес эти изменения?

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

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

Чтобы помочь устранить эти проблемы, React 18 вводит новую проверку Strict Mode, предназначенную только для разработчиков. Эта новая проверка будет автоматически размонтировать и повторно монтировать каждый компонент, когда компонент монтируется в первый раз, восстанавливая предыдущее состояние при втором монтировании.

Дополнительные обсуждения на GitHub, которые дали гораздо больше информации о причинах изменений в StrictMode:

  • Добавление многоразового состояния в StrictMode
  • Как поддерживать многоразовое состояние в Effects

Резюме

React 18 вносит изменения, которые могут привести к неожиданному опыту разработчика и более беспорядочным консольным журналам, когда одни и те же сообщения срабатывают дважды. Он также вводит различное поведение приложения при работе в режиме разработки и в режиме производства, что, вероятно, нежелательно.

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

Оцените статью
Procodings.ru
Добавить комментарий