Галоўная / Артыкулы / Фрагменты React і StrictMode: простейшая маркапінг і ранэйскія выяўленні багоў

Фрагменты React і StrictMode: простейшая маркапінг і ранэйскія выяўленні багоў

Дазвольце дазнаць, як фрагменты React групаваюць элементы без дадзейшых кантэйнероў DOM, і як двойная запуск режыму StrictMode, прызначанага толькі для разработкі, адкрывае нечыстыя процесы выкарыстання элементаў і ўплывы на ўтварэнне інтерфейса.

976 слоў

Два фічы React, які ніколі не адрабатваюць нічога на экране, пры тым утвараюць майже кожную дрэва компанентаў: Fragments і StrictMode. Fragments заходзяцься пра тое, каб ваш DOM быў вільны ад элементаў-обгортакоў, якія існуюць толькі для задоволення патрабавакаў JSX, тады як StrictMode спецыяльна стварае напругу ў вашых компанентах пад час розработы, каб нечыстая логіка стала видна раней, чым яе побачуць корыстнікі.

Чаму JSX патрабуе аднае коранявай точкі

JSX кампілюе кожны тэг у вызыв функцыі, таму два сяброўскія тэгі, якія вяртаюцца разам, ёсць двумя значэннямі, калі ж патрабуецца толькі адна. Гэта не дазволяе кампіляцыі:

return (
  <h1>Hello</h1>
  <p>Welcome</p>
);

Традыцыйны спосаб рашэння быў у тым, каб загорнуць сяброўскія тэгі ў div:

return (
  <div>
    <h1>Hello</h1>
    <p>Welcome</p>
  </div>
);

Дадатковы вузол мае своія наследкі: ён паглыбляе структуру DOM, наражае на проблемы лейяуты типу flex або grid, якія патрабуюць прымітных дзецячых элементаў, ускладнюе выбіранне селектараў і можа прызвесці да неваліднага або менш доступнага HTML.

Групаванне без обгортака

Fragment агрупавае дзецяў для React без стварэння жадных элементаў DOM. Короткая сынтаксіс — это пара пустых тагоў:

return (
  <>
    <h1>Hello</h1>
    <p>Welcome</p>
  </>
);

Явны формат React.Fragment рабіць тое ж самае і ўсёрэшчы неабходны, калі трэба перадаць проп:

return (
  <React.Fragment>
    <h1>Hello</h1>
    <p>Welcome</p>
  </React.Fragment>
);

Зроблены HTML содержыць толькі h1 і p. Прырост карыстоўнасці мінімальны; справжняя выгода — правільная маркапаўка.

Верненне элементаў-братоў

Компонент, які стварае калькі роўназначных элементаў, можа заставіць распакоўку свайму абяцелю:

function Card() {
  return (
    <>
      <h2>Title</h2>
      <p>Description</p>
    </>
  );
}

Фрагменты з ключамі ў лістах

Калі працуеце з дадзенням, дзе кожны элемент стварае больш ад однаго элемента, React все раве патрэбны стабільны key для кожнага элемента. Короткая сынтаксіс <> не можа прыймаць атрыбуты, таму выкарыстоўваеце React.Fragment з ключам:

items.map(item => (
  <React.Fragment key={item.id}>
    <h2>{item.title}</h2>
    <p>{item.description}</p>
  </React.Fragment>
));

Клеткі табелі і рядкі

Тэблы HTML маюць строгія модель кантэнту: элемент tr можа мячыць толькі элементы td або th. Элемент div, які ўкладае іх, там не дапускаецца. Фрагмент дазваляе компоненту дапраўляць калькі клетак у ряд, які належы ўжо його абяцелю:

function Row() {
  return (
    <>
      <td>A</td>
      <td>B</td>
    </>
  );
}

Што пераказвае StrictMode

StrictMode не выводзіць нічога, не дадае жадных элементаў і не мае ніякога адзычлена ў версіях для практычнага выкарыстоўвання. У режыме разработкі ён уваўлекае дадатковыя пераказванні, у тым часе як:

  • паведамленні пра методы жыцёвага циклу класаў, якія счыляюцца небезпечнымі, такія як componentWillMount
  • паведамленні пра застарэлыя API, такія як рэферэнсы страк і findDOMNode
  • двойны выклік тэла компонента, функцый ініцыялізацыі і апдэйта, каб выявіць нечыстае выкананне
  • выкананне эфектаў чераз дадатковы цыкл настройкі, чысткі і зноўной настройкі пад час запуску, каб выявіць неадказнае чыстканне

Точны ўказаны список змініўся ў разных версіях React, таму пераканайцеся, што вы бачыце актуальную документацыю для вашай версіі.

Намеравана двойная рэндарызація

Разглянем компонент, які логуе падчас рэндарызаціі:

function App() {
  console.log("Rendered!");
  return <h1>Hello</h1>;
}

Пад StrictMode пад час розрабоцы консоль паказвае цю прыемку два разы:

Rendered!
Rendered!

Гэта ўзято за прымет. Функцыя рэндарызаціі павінна быць чыстой: пры тых сабе props і стане ў яе вяртаецца той самы выхід, і ў яе не змінюецца нічога паza ёй. Выкліканне яе два разы прыводзіць да нарушэнняў, такіх як змяна спакульнай зменной, і да візуальна некоректных рэзультатаў. Чыстасць мае значэнне, таму што можа пачысцца адночасная рэндарызація, якая може стартаваць, паставляцца, адкладвацца чы працаваць занова, і код, які гадае, што за кожную змяну вядзецца толькі адна рэндарызація, не будзе працаваць за такых умов.

Увімкненне

Абгорніце дрэво, якое вы хочаце пераканацца, зазвычай усю аплікацыю, на корэне:

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Эфекты ў режыме StrictMode: массив залежнасцяў — не спосаб рашэння

Ёсць эфект без массива залежнасцяў. Ён выконваецца пасля кожнага атрыбутавання, таму кожная зміна спрычыняе ўтварэнне новага запиту:

useEffect(() => {
  console.log("Fetching...");
  fetch("/api");
});

Дадзенне пустога массива обмежвае выконанне эфекта толькі часом яго монтавання:

useEffect(() => {
  console.log("Fetching...");
  fetch("/api");
}, []); // stable dependency

Такая змяна ў правілы, але яна не запобегае двойнаму выконанню у режымі разработки. Зачынення React 18 StrictMode монтавае компонент, выкананыя яго функціі чысткі, і зноў монтавае яго, таму эфект з [] працюе там два разы. Двойнае выкананне — гэта сігнал, а не баг. Праўы спосаб рашэння — функцыя чысткі, якая робіць другае выкананне безнэпакойным, зазвычай абрываючы першы запит за дапамою AbortController або ігнаруючы яго рэзультат за дапамою флага. Такі эфект таксама ў безпецы ад практычных перемонтаванняў у режыме выпуску.

Паралельна

  • Мэт: Фрагменты групаваюць элементы; StrictMode выяўляе багі.
  • Выход DOM: ніхто з іх не дадае элемента.
  • Уплыв на працэўную сістэму: няма жадных наследкав для або таго.
  • Працовае падзея: Фрагменты адрасаваюцца звычайна; StrictMode двойна вызывае адрасаванне та эфекты толькі пад час розработы.
  • Што вы атрымуеце: чыстейшы, правільны маркап у працоўнае супрацоўванне проты прогнозавальнага коду, захіщанага ад побачных эфектаў.

Мінімальная наладка для працы

Компонент нижэй вяртае два братскія элементы через Фрагмент:

export default function App() {
  return (
    <>
      <h1>Hello World</h1>
      <p>Rendered using Fragments</p>
    </>
  );
}

Файл-вхід адрасавае яго ўнутры StrictMode, таму будзь-якая нечыстая логіка, яку вы дадаеце пазней, будзе негайна адкрыта пад час розработы:

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Ключовыя выводы

  • Вжывайце Фрагмент кожны раз, калі елемент-обгортак існаваў бы толькі для задоволення трэбаванняў JSX, і вжывайце React.Fragment з key у спісах.
  • У разработцы заставіце StrictMode працаваць; подвойныя лог-запісы і подвойныя эфекты ўмышлена викорыстоўваюцца як діагностычныя засобы.
  • Штучкамі з завісамі не лячыце проблему подвойнага выканання эфектаў — яе трэба рашыць праз правильную чыстку коду.