Паспрацаванне з React: адкладкі стану ў пікселі экрана
Як фазы render, reconciliation і commit у React з’єднуються з процесам відрисовування браузером: layout, paint і composite, від оновлення стану до фактичних пікселів екрана.
Крыніцы: Rendering Lifecycle in React: From State Update to Pixels on the Screen
Працюючы з React, часта суём фразу "компонент перерэндараваецца". Але што на самай працэ ўсё-такі значыць перерэндараванне?
У гэтым контексте выклікаюцца калькі практычных запытанняў. Чы Реакт негайна дадае апдэйты DOM, калі змянюецца стан? Чы змена стану прыводзіць да таго, што кожны компонент павінен перерэндаравацца? І калі Реакт зноў перерэндараваець які-небудзь элемент, чы гэта значыць, што браузер негайна перамальоввае весь сторнак? Як выявілася, нічога з гэтага не ўсуне.
Ёнколі хочаце правильна зрозумець жыцёвы цикл перерэндаравання, трэба разумець двы аднальныя системы, якія працуюць разам:
Свой жыцёвы цикл перерэндаравання Реакта і практыка перамальоввання браузера.
Калі вы паблічнае, як заўязаныя этыя два системы, такія поняття, як прымирэнне, фаза адправкі, useEffect, useLayoutEffect, павтарэнне адрасаўвання і мемаізацыя, перестаюць здавацца чамусь магічным і становяцца зрозумелымі.
1. Загальная картына
У загальных рысах прабег справы выглядае так:
User Interaction
│
▼
State / Props Change
│
▼
┌──────────────────────┐
│ React Render │
│ │
│ Component executes │
│ New UI is returned │
└──────────┬───────────┘
│
▼
Reconciliation
│
▼
┌──────────────────────┐
│ Commit Phase │
│ │
│ Update real DOM │
└──────────┬───────────┘
│
▼
┌──────────────────────────┐
│ Browser Rendering │
│ │
│ Style → Layout → Paint │
│ → Composite │
└────────────┬─────────────┘
│
▼
Screen
Галоўны вывад здэсь такі:
React вычышае, як павінна выглядаць інтэрфейс і якія змены ў DOM неабходны. Потым браузер берае этыя змены і ператварае іх у рэальныя пікселі на экране.
2. Што значыць «адрасаўванне»?
Тэрмін «адрасаўванне» вжываецца ў болей чым аднам значэнні.
У контексте React адрасаўванне зазвычай значыць гэта:
React вызывае функцыю вашага компонента і вычышае, як павінен выглядаць рэзультатны інтэрфейс.
Разглядзім этот компонент:
function Counter() {
const [count, setCount] = useState(0);
return (
<button>
Count: {count}
</button>
);
}
Калі React яго атрыбутуе, выконваецца тэла функцыі:
Counter()
↓
returns React element
↓
<button>Count: 0</button>
Гэта не значыць, што браузер уже намаліў кнопку на экране.
Перш чым адбудзецца ўсё візуальна, React все ж должен выявіць, чы рэальна DOM патрэбуе змены.
Корача кажучы:
React Render
≠
DOM Update
≠
Browser Paint
Атрыбутаванне та апдэйт DOM — гэта два разныя процесы.
3. Жыцёвы цикл атрыбутавання браузерам
Перш чым заглыбляцца ў внутрошняе строенне React, корыстна зразумець, што сам браузер робіць.
Уявіце, што у вас ёсць такі маркап:
<h1 class="title">
Hello World
</h1>
У поўнасці ўзаедна з гэтым стайл-шытом:
.title {
color: red;
font-size: 30px;
}
Перш чым гэты контент хоць як будзе візуальна прыказаны, браузер пераходзіць праз ряд актыўных внутрошняях крокаў.
Спрасцаваная версія гэтага процесу выглядае так:
HTML
↓
DOM
↓
CSS
↓
CSSOM
↓
Render Tree
↓
Layout
↓
Paint
↓
Composite
↓
Screen
Разберамся з кожным этапам.
4. HTML → DOM
Браузер чытае HTML і стварае DOM, якое ў складчыні значыць Model об’екта дакумента.
З урахоўваннем гэтага маркапу:
<body>
<h1>Hello World</h1>
<p>Welcome</p>
</body>
Браузер стварае дрэваўую структуру прыблізна такой:
Document
│
└── body
├── h1
│ └── "Hello World"
│
└── p
└── "Welcome"
Пасля чаго JavaScript можа безпасэродзе запытваць і маніпуляваць гэтай структурам:
document.querySelector("h1");
По суты, DOM адпавядае на аднае пытанне:
Калі элементы існуюць на сторанцы?
5. CSS → CSSOM
Паралельна з DOM браузер таксама парасканаввае ваш CSS і стварае CSSOM, тое ў складчыні Model об’екта CSS.
Напрыклад:
h1 {
color: red;
font-size: 30px;
}
На адной з гэтых падстав браузер выважае, якія стылі паслядуюць для кожнага элемента.
Канцэптуальна, гэта выглядае так:
h1
├── color: red
└── font-size: 30px
CSSOM адпавядае на іншае пытанне:
Як следуе візуальна настроіць кожны элемент?
6. DOM + CSSOM → Дрэва рэндараўання
Далей браузер з’еднае DOM і CSSOM, ў результате чаго ствараеяцца Дрэўо адраджэння.
Є адна тонкасць, якаю варта згадаць:
Не кожны вузол у DOM будзе представлены ў Дрэўе адраджэння.
Напрыклад, возьмім такі маркап:
<div class="hidden">
Hello
</div>
У поўнасці разам з гэтым правілам:
.hidden {
display: none;
}
Элемент div ўсё ж існуе ў DOM:
DOM
└── div
Але осколькі ён мае:
display: none;
ён цэлкам адключаецца з візуальнага Дрэўа адраджэння.
7. Распакоўка
Калі браузер точна ведае, якія элементы трэба паказаць, ён вырахоўвае іх геаметрыю.
Гэта включае вычысленне такіх показнікаў, як:
- Шырына
- Высота
- Пазіцыя
- Маржы
- Падпертыя
- Координаты
- Як элементы адносуюцца прасторова адна да другой
Возьмім гэтае правіла як прыклад:
.box {
width: 200px;
height: 100px;
margin-left: 50px;
}
Браузер павінен выдаваць конкрэтныя значэння па такім прыемліванні:
x = 50px
y = ...
width = 200px
height = 100px
Этап вычыслення называецца Layout, і яго таксама часта адначасова называюць Reflow.
8. Paint
Пасля завершэння форматавання браузер мае координаты для кожнага відразлівага элемента.
Наступны крок — адразліванне таго, як на самай працэ выглядаюць гэтыя элементы.
Разглядзім такое стайліванне:
.box {
background: blue;
color: white;
border: 2px solid black;
}
Процэс Paint абарачвае такія элементы:
- Фон
- Тэкст
- Краі
- Цені
- Адразліванні
- Іншыя візуальныя элементы
У парадку:
Layout
↓
Paint
↓
Pixels
9. Composite
Сучасныя браузеры можаюць раздзеліць сторанку на кальколька аднальных шароў.
Напрыклад:
Layer 1 → Page background
Layer 2 → Header
Layer 3 → Content
Layer 4 → Modal
Пасля гэтага композітор браузера з’еднае всі гэтыя шары ў адны адразліванне, які пасля выйдае на экран.
Адзінкія атрыбуты CSS, такія як:
transform
opacity
Зазвычай гэта можа быць анімавана толькі за дапамою композіцыі, чым ухілваецца ад болей сложной роботы з макетам, якая трэбаецца для атрыбутаў, якія вплываюць на геаметрыю.
Гэта ў частыні прычыны, чаму анімаванне transform зазвычай ўважаецца аптимальным падходам.
10. Жыцёвы цикл рэндарування React
Калі мы вже розглянулі сторону браузера, давайце перейдзем да таго, як React керуе рэндаруванням.
Прыдатны ментальны модэль дзеліць гэты процес на чатыры стадіі:
1. Trigger
2. Render
3. Reconciliation
4. Commit
5. Browser Rendering
Давайце розглянем кожную з іх.
11. Фаза 1 — Актывацыя
Перш чым ўсё інше пачнёцца, React патрэбны сігнал, які гаворыць:
"Інтерфейс можа патрабаваць апдэйтаў."
Гэты сігнал называецца актывацыяй рэндарування.
Тыповыя прычыны актывацыі включаюць:
1. Апдэйт стану: setCount(10);
2. Змена пропсаў: <Child count={count} />
Калі родны компанент перыядруецца з новай значэннем для count, яго дзеціны компаненты можаць атрымаць новыя пропсы як наследак.
3. Апдэйт контекста: useContext(MyContext);
Калі-небудзь зменяецца значэнне, чытана з контекста, компаненты, якія яго выкарыстоўваюць, можаць патрабаваць апдэйта.
4. Апдэйт зовнішняе базы дадзеных: Бібліятэкі і API таксама можуць спрыяць апдэйту React.
Прыклады включаюць:
Redux
Zustand
useSyncExternalStore
Першы запуск аплікацыі таксама лягае ў кантэкст спрычыны апдэйта.
12. Фаза 2 — Render
Калі React атрымлеў інформацыю пра апдэйт, ён пераходзіць у фазу render, дзе запускае компаненты, каб вырашыць, які будзе новы інтерфейс.
Возьмім такі прыклад:
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
);
}
Спачатку count доравнае 0. React вызывае Counter() і стварае:
<button>
Count: 0
</button>
Калі нажата кнопка і запускаецца гэты код:
setCount(c => c + 1);
count становіцца 1, і React парадзеўна выкананая компонента, чыго рэзультат:
<button>
Count: 1
</button>
13. Важнае: Render НЕ значыць апдэйт DOM
Эта ўлучнае размежаванне ў модэлі React.
Калі React выкананая гэтую функцыю:
function Counter() {
console.log("Counter rendered");
return <button>Count: 1</button>;
}
яна проста вырахоўвае, як дэвэльперскі інтерфейс дзеўэльнае выглядаць. Гэта не прымусова значыць, што DOM змяніўся або што браузер перамалюваў які-небудзь элемент.
Рэальная последовасць выглядае так:
Component executes
↓
React creates new element representation
↓
Reconciliation
↓
Determine required DOM changes
↓
Commit changes
Што прыводзіць да ключовага правіла:
Выкананне компоненты не прымусова ператвараецца ў апдэйт DOM.
14. Фаза 3 — Спакоі
На гэтым этапе React парабягае стары і новы дэвэльперскі інтерфейс, каб з’ясаваць, што самэўна зменілася.
Сказаўм, што пакананая структура выглядала так:
button
└── "Count: 0"
А новая структура выглядае так:
button
└── "Count: 1"
React можа вывучыць:
button → same
text → changed
Таму яму трэба зменіць толькі тую частку DOM, яка насправды зменілася:
button.textContent = "Count: 1";
Галоўная мета — ухіліцца ад разбірання і практычнага стварэння всёго дрэва DOM, калі зменілася толькі невелика частка.
15. Ключы і супрацоўка з данымі
Ключы маюць вялікое значэнне, калі React працуе зі спісамі.
Напрыклад:
items.map(item => (
<li key={item.id}>
{item.name}
</li>
))
React выкарыстоўвае ключы, каб стежыць за тым, які элемент ёсць каму праз рэндары. Падазроўваю, што вы пачынаеце з:
Before:
A
B
C
і заканчваеце з:
After:
A
C
За наявнасці стабільных ключоў React можа правильна вывучыць:
A → same
B → removed
C → same
Это дае React набліжна болей надзеяныя даны для працы пад час супрацоўкі з данымі. Ухіліваюцеся ад выкарыстоўвання індэксаў масівы як ключоў, калі элементы спісу могу быць пераранжаваны, даданы або адключаны.
16. Фаза 4 — Затверджэння
Калі React выявляе, што трэба зменіць, ён пераходзіць да этапу фіксацыі, дзе насправды застосоўвае гэтыя змены да рэальнага DOM.
Уявіце сабе элемент кантакту, чыё пазначэнне пасля завершэння гэтага этапу зменяецца з нуля на адин.
У гэты момент внутрашняя структура React і рэальны DOM нарэшце становяцца адпаведнымі.
Этап фіксацыі — это окремы крок, аднародны з этапам выканання:
Render Phase
↓
Calculate what should change
Commit Phase
↓
Actually apply DOM changes
17. Этап выканання проты этапу фіксацыі
Розумеўшы гэты разлік, ёсць адна з найпашыльнейшых тэм, якіяя спрашваюць у кандыдаў на адзінку.
Этап выканання
У гэтым этапе React:
- Выканае функцыі компонентаў
- Выявляе наступную версію інтэрфейсу
- Выконвае супрацоўку з данымі
- Выявляе, што трэба зменіць
Component
↓
React elements
↓
Reconciliation
Этап фіксацыі
У гэтым этапе React:
- Выконваецца фактычныя мутацыі DOM
- Апдэюецца ўсе рэферэнсы
- Выконваюцься эфекты макетавання, якія зв’язаны з гэтым апдэйтом
React result
↓
Real DOM
Ёсць спроставаныяе зображэнне прабегу:
React
│
▼
┌──────────────┐
│ Render Phase │
└──────┬───────┘
│
▼
┌───────────────┐
│ Commit Phase │
└──────┬────────┘
│
▼
Real DOM
18. Што выканаецца пасля Commit?
Калі фаза commit завершыцца, браузер перэймае кераванне і заўважае, што DOM змяніўся.
Залежна ад таго, што змянілася, браузеру можа знадобіцца працаваць па калькам стэпеняў:
DOM Changes
↓
Style Calculation
↓
Layout
↓
Paint
↓
Composite
Не кожная змяна выклікае неабходнасць адбыцца ўсіх гэтых стэпеняў, каб была роўнасць — напрыклад, можа знадобіцца толькі перазначэнне кольору, без неабходнасці повнага перасчытку макета.
Гэта самэ тое месца, дзе власны цыкл жыцця React перадае кераванне практыцы рэндарування браузера, якая была описана раней.
19. useLayoutEffect
useLayoutEffect выклікаецца пасля таго, як React адбыў змены ў DOM, але да таго часу, калі прыстрой перзора можа адразу паказаць новы візуальны фат.
Прырода выклікання выглядае так:
React Render
↓
Commit
↓
DOM updated
↓
useLayoutEffect
↓
Browser Paint
function Tooltip() {
const ref = useRef(null);
useLayoutEffect(() => {
const rect = ref.current.getBoundingClientRect();
console.log(rect.width);
}, []);
return (
<div ref={ref}>
Tooltip
</div>
);
}
Этот хук є правым інструментам, калі вам патрэбна:
- Апыліць элементы ў DOM
- З’явіцца текущыя значэння лейауту
- Здзейсніць візуальныя налаштаванні сінхронна, перш чым корыстнік побачыць ўсё
Адна парада: якщо робота ўнутры useLayoutEffect є важкай, гэта можа спамітліць процес адрасавання візуальнага фату і зробіць інтерфейс медленным.
20. useEffect
useEffect, на адміну, прызначаны для эфектаў, якія не павінны блакаваць процес адрасавання прыстрою перзора.
useEffect(() => {
fetch("/api/products");
}, []);
Render
↓
Commit
↓
Browser Paint
↓
useEffect
Актуальныя деталі планавання є трохи болей складнымі, чым гэта, але ключовая практычная правіла ёсць:
Выкорыстоўваеце
useLayoutEffectтолькі тады, калі ўсё павінна выйсці раней, чым браузер адрасавае елементы; для всьога, што можа выконвацца пасля таго, як інтэрфейс вже стаў видным, выкорыстоўваецеuseEffect.
21. Полны прыклад
import { useEffect, useLayoutEffect, useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
console.log("Render");
useLayoutEffect(() => {
console.log("Layout Effect");
});
useEffect(() => {
console.log("Effect");
});
return (
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
);
}
Канцэптуальна, последовасць запуску задач выглядае так:
User clicks button
↓
setCount()
↓
State update scheduled
↓
Counter() executes
↓
"Render"
↓
React reconciles
↓
React commits DOM update
↓
"Layout Effect"
↓
Browser paints updated UI
↓
"Effect"
22. Чы выклікае перерэндарынг абяцелі перерэндарынг дзецячага элемента?
Возьмім такі прыклад:
function Parent() {
const [count, setCount] = useState(0);
return (
<>
<button onClick={() => setCount(c => c + 1)}>
{count}
</button>
<Child />
</>
);
}
Калі апдыяецца count:
Parent renders
↓
Child is encountered
↓
Child may render as part of reconciliation
So,
Parent state update
↓
Parent render
↓
Child can render
Гэтая працоўнасць є адной з прычын, чаму існуе React.memo як засоб для оптымізацыі.
23. React.memo
Падазроўваюце, што у вас є:
const Child = React.memo(function Child() {
console.log("Child rendered");
return <p>Hello</p>;
});
Якщо абяцель перерэндарынгуе, але пропсы, якія пасылаюцца дзецячаму элементу, застаюцца ідэнтычныя па адрасе, React можа зовсамна праігнораваць перерэндарынг таго мемуізаванага элемента.
Ось гэтая ідея візуальна:
Parent update
↓
Parent renders
↓
React.memo checks Child props
↓
Props unchanged
↓
Skip Child render
Але пам’ятайце:
React.memoдае вам шлях ад спрытнасці — ён не гарантуе, што компонент ніколі больш не будзе атрыбутаваны.
Змены контэкста, внутранія стан і іншы факторы все ўсё можу змусіць яго адкорэгавацца, незалежна ад мемоізацыі.
24. useMemo і useCallback
Этыя два хукі часта неправильна разумеюцца.
useMemo: Ён мемоізуе вырахаваную значэнне.
const result = useMemo(() => expensiveCalculation(data), [data]);
useCallback: Ён мемоізуе кансэкт функцыі.
const handleClick = useCallback(() => {
doSomething(id);
}, [id]);
Оба дзеясно ўжыткаваныя у ситуаціях, калі роўнасць кансэкта мае значэнне для ухіленьня ад павтаральной роботы — насуперак усьму, калі перадаюцца пропсы мемоізаваным дзецячым компонентам.
Але ўжыванне іх усюды за замовчаннем часта прыносіць дапэўню сложнасць у ваш код без рэальной падышкі ў спрытнасці.
25. Адрадзіцельне выкананне у React не ўсё роўна адрысаванню элементаў у браузеры
Этот момент варта часткаці яшчэ раз.
Уявіце сабе следуючы компонент:
function App() {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(c => c + 1)}>
{count}
</button>
<p>Hello</p>
</div>
);
}
Калі змянюецца count:
App renders
↓
New React tree created
↓
Reconciliation
↓
Only count text differs
↓
Commit small DOM update
↓
Browser rendering
React не обавязкова будзе перабудаваць гэты маркап з нуля:
<div>
<button>...</button>
<p>Hello</p>
</div>
26. Вярчыны DOM — правильная канцэпцыя
Часта можна пабачыць тверджэнне, што React выкарыстоўвае Вярчыны DOM, каб прышвыдзіць роботу браузера. Гэта спрасцаванне.
На самай працэ React зберагае внутраній опис UI ў памяці і выкарыстоўвае процэс супаралелення, каб з’ясаваць, што змінілася.
Сам браузер не мае панявы пра Вярчыны DOM. Ён работае толькі з такімі элементамі, як HTML, DOM, CSS і, ў канечнай лініі, пікселі.
Канцэптуальна, працэс выглядае так:
React Component
↓
React Element Tree
↓
Reconciliation
↓
DOM Mutations
↓
Browser
↓
Pixels
Вярчыны DOM ніколі не ўтвараюцца як рэальны элементы, якія браузер адразу відрасцварвае.
27. Перывыдрашчэванне проты перамальовкі
Это два разныя панявання, якія не трэба сплутваць.
Перывыдрашчэванне у React
Это тады, калі функцыя компонента выканана знову — практычна, Component() запускаецца занова.
Перамальовкі браузером
Это тады, калі браузер перамальоввае пікселі на экране чераз змяну якой-небудзь візуальной характэрыстыкі — це етап Paint.
Таму памятаце: перывыдрашчэванне у React не ўзроўнаважваецца з перамальовкай браузером.
Пэўна можлівасць, што компонент зноў будзе відрасцварвацца, але залишыць тую ж структуру DOM. Навпакі, браузер можа перамальовваць пікселі з прычын, якія не маюць нічынага з відрасцварванням якога-небудзь компонента React.
28. Пераранжаванне проты перамальовкі
Возьмімо такій прыклад: element.style.width = „500px“;
Зменшэнне шыроўны гэтага элемента зазвычай вымушвае пераслікваваць распаковку:
Style
↓
Layout
↓
Paint
↓
Composite
Тепер паравярцімы яго з: element.style.backgroundColor = „red“;
У гэтым случае браузер зазвычай не патрабуе перарахоўваць геаметрычныя параметры занова:
Style
↓
Paint
↓
Composite
А для певных змян у трансфармацыях чыстаце адкрытасі браузер можа патрабаваць толькі:
Composite
Розумеўце гэтага разліку ёсць важная частка падчас оптымізацыі анімацый чыстаце інтэрфейсоў, якія маюць вялікія выканы.
29. Застосаванне гэтага ў рэальнай сцэнарыі React
Уявіме типовую сторонку товара ў інтернет-магазіне, структураваную так:
Product Page
├── Navbar
├── Product Gallery
├── Product Information
├── Add To Cart
├── Reviews
└── Recommendations
Спадзяймося, ўжо корыстувач нажмае кнопку Дадаць у кошык, якая апдэйтуе колькісць у кошыку.
Канцэптуальна, парадоксы змян можа выглядаць так:
User clicks "Add to Cart"
↓
Cart state updates
↓
React schedules update
↓
Relevant components render
↓
React reconciles new tree
↓
Only required DOM changes are committed
↓
Browser performs necessary rendering work
↓
Updated cart count appears
У добра параджанаванам прыкладзе програмы, такая зміна колькасці тавароў у кошыку не павинна прыводзіць да непатрэбнага перабудоввання всіх элементаў інтэрфейсу. Самэ гэта ёсць прычыной таго, чым так важлівыя рашэння ў паводзе з межамі компанентаў, месцем зберагчы стану, тэхнікамі мемаізацыі і загальной архітэктурой адраджвання.
30. Калі дорога процэс адраджвання стае проблемай карыстоўнасці
function ProductList({ products }) {
return products.map(product => (
<ExpensiveProductCard
key={product.id}
product={product}
/>
));
}
Падазроўваючы, што гэты список адраджвае 10 000 тавароў, а якаясь несувязаная зміна стану спрычыняе непатрэбную роботу ў вельмі большай колькасці компанентаў — карыстоўнасць можа значна паспадзіцца.
Пашырэныя методы кампенсаціі включаюць:
React.memo
+
Stable props
+
useMemo/useCallback where justified
+
Virtualization
+
Pagination
+
Code splitting
Для ўсё бол большых списакоў віртуалізацыя часта выказваеся ўсё бол эфектывай:
10000 items
↓
Only visible ~20-50 items rendered
31. Як адраджвання взаімаеся з паралельным React
Новыя версіі React маюць болей прыглушаныя можлівасці планавання. React можа надаць прыоритет разным апдэйтам і, калі гэта цяплы, націснуць або адклаць работу з выкарыстоўванням дадзеных.
Ключовая канцэпцыя, якую трэба памятаць:
Render work
↓
Can be scheduled
↓
Can be interrupted in modern React
↓
Eventually committed
Самэ гэтая прычына, чаму пабочныя эфекты не должны знаходзіцца ў логіцы выкарыстоўвання дадзеных компонента:
function Component() {
fetch("/api/data"); // ❌ Side effect during render
return <div>Hello</div>;
}
У замяну трэба выкарыстоўваць хук effect або падходячы шаблон запрашання дадзеных. У ідеале фаза выкарыстоўвання дадзеных должна заставацца чыстай.
32. Прычыны чыстага выкарыстоўвання дадзеных
Канцэптуальна компонент React должен вядзець ся як чыстая функція:
UI = f(props, state)
Пры аднаковых пропах і стане ён завжды должен атрадзіць той самы інтерфейс. Напрыклад:
function Greeting({ name }) {
return <h1>Hello {name}</h1>;
}
Такая поведзенчасць є прыглушанай і безпечной.
Натоўп, выкарыстоўвання чаго-то такога ўнутрь фазы выкарыстоўвання дадзеных є проблематычным:
function Component() {
localStorage.setItem("x", "1"); // ❌
fetch("/api"); // ❌
return <div>Hello</div>;
}
Это вводзьце паблічных эфектаў у фазу, яюяя React можа запускаць больш чым раз, або планаваць у нечаканных спосабах.
Паблічныя эфекты належаць іншым месцах — у функціях эфектаў, обрабоўчыках змян, або механізмах запрашэння дадзенаў, якія апрантка прысвайчае.
33. Жыцёвы цикл атрыбутавання — Полны ментальны модэль
USER ACTION
│
▼
State / Props Update
│
▼
React Schedules Work
│
▼
┌──────────────┐
│ RENDER │
│ │
│ Components │
│ execute │
└──────┬───────┘
│
▼
Reconciliation
│
▼
┌──────────────┐
│ COMMIT │
│ │
│ DOM mutation │
└──────┬───────┘
│
▼
useLayoutEffect
│
▼
Browser Rendering
│
▼
Style Calculation
│
▼
Layout
│
▼
Paint
│
▼
Composite
│
▼
SCREEN
│
▼
useEffect
Паўтарычныя запитанні пад час адбору
Q1. Чы гэта апдэйт стану негаразда апдэйтуе DOM?
Нята. Апдэйт стану проста планавае задачу для выканання ў React. React атрыбутавае компонент, праконтроўвае выход проты таго, што было раней, і толькі пасля чаго выкарыстоўвае тыя змены DOM, якія насправды неабходны.
setState
↓
Render
↓
Reconciliation
↓
Commit
↓
DOM
Q2. Чы кожна атрыбутаванне ведае да апдэйту DOM?
Нята. React можа атрыбутаваць компонент і ўсё ж вырашыць, што атрыбутаваная візуальная структура ідэнтычна той, якая вже ў экране, і ў такім случае ён не зменяе DOM.
Render
↓
Compare
↓
No meaningful DOM difference
↓
No DOM mutation
Q3. Чы гэта перыядражаванне ў React прыводзіць да перамальвання экрана браузерам?
Ня. Прырэштаванне ў React і мальваванне ў браузеры — гэта два незалежныя процесы.
React Render ≠ Browser Paint
Q4. Што значыць супраўжнеча?
Супраўжнеча — гэта спосаб, якім React пароўнае ўсё няўчаса вырахаваныя структуры UI з паказванымі ранейша, каб выявіць, што самэўсёлкі трэба змяніць.
Q5. Што адбываецца на стадіі commit?
Пад час commit React прыкладзае неабходныя змены да сэрвіруючай среды — напрыклад, апдэйтуе рэальныя вузлы DOM у браузеры.
Q6. У чым разліка между useEffect і useLayoutEffect?
Просты спосаб згадаць гэта:
useLayoutEffect
→ after DOM commit, before paint
useEffect
→ after commit and generally after paint
Выкорыстаўце useLayoutEffect, калі вам трэба синхронна вылічыць або скоректаваць лейаут прытаму, перш чым корыстнік побачыць новую картінку. Для большасці парадоксальных эфектаў, якія не трэба блакаваць процес атрыбутавання, выкорыстаўце useEffect.
Q7. Чы гэта спрыяе атрыбутаванню компонента?
Тыповыя прычыны – пачатковая інсталляцыя, апдэйт стану, паўторны атрыбутавання роднічага компонента, змяна параметраў, апдэйт контексту або данні з зовнішняе базы.
Q8. Як можна оптымізаваць атрыбутаванне? [IMP]
Уместа таго, каб за замовчаннем выкорыстоўваць useMemo у всіх месцах, спачатку з’ясавайце, дзе самае большая перашкода. Потым рассмотріце наступныя падходы:
1. Храніце стан поблізу месца, дзе ён выкорыстоўваецца
Утримайцеся ад структуры, у якой стан знаходзіцца на верхнім роўні, а кожны падкомпонент залежыць ад яго:
App
↓
Everything depends on state
prefer:
Feature
↓
Local state
Лепшае выбаранне — вжыць шчырэйшую пазуху, калі глобальны стан на самай працэ не патрэбен.
2. Выбірачна мемаізацыя дорогіх компанентав
const ProductCard = React.memo(ProductCardComponent);
3. Следзіце за стварэнням об’ектаў, якія наражаюць мемаізацыю на абранне
У замяну на паўтаральнае стварэнне новага об’екта ў тым жа месцы так:
<Child config={{ theme: "dark" }} />
Можа знадобіцца стабільны апуск, якщо Child ўкладзены ў React.memo і ідэнтычнасць мае значэнне — але не рашайце гэтыя проблемы, пакуль яны насправды не стануць проблемай.
4. Віртуалізацыя дужых спісоў
У замяну на адразуве выкананне ўсіх 10 000 вузлаў DOM, выканайце толькі тыя, якія зараз відначаюцца.
5. Адкладзенне завантажэння дорогіх функцыяй
const AdminDashboard = lazy(() => import("./AdminDashboard"));
Гэта зменшае колькасць JavaScript-кода, які павінен быць завантажаны і выкананы з самага пачатку.
6. Выбірайце тэхнікі выканання, якія падтрымваюцься браузерамі
Калі час, выкарыстоўваюце дышэвыя атрыбуты, такія як transform і opacity, і ухіліцеся ад прымусовых дорогіх перасчыткаў макета ў кожным кадре.