Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Ререндер при зміні контексту». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)Коли `value` у `Context.Provider` змінюється (за посиланням), React вважає, що контекст оновився, і всі компоненти, які викликають `useContext`, отримують нове значення й перемальовуються. **Ключове:** React порівнює не вміст контексту, а посилання на об'єкт `value`, тому новий об'єкт при кожному рендері "змінює" контекст навіть без реальних змін даних.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Чому всі споживачі контексту ререндеряться Коли ти створюєш контекст: ```javascript const ThemeContext = createContext(); ``` і використовуєш його так: ```javascript <ThemeContext.Provider value={theme}> <Header /> <Footer /> </ThemeContext.Provider> ``` всі компоненти всередині `Provider`, які роблять: ```javascript const theme = useContext(ThemeContext); ``` **підписуються на це значення** (`value`). --- ### Як працює механізм 1. `Context.Provider` зберігає **одне значення** - `value`. 2. Кожен компонент, що викликає `useContext(ThemeContext)`, підписується на це значення. 3. Коли `value` змінюється (за посиланням), React **вважає, що контекст оновився**. 4. У результаті **всі підписані компоненти** отримують нове значення -> React **перерендерює їх** з новим контекстом. --- ### Приклад ```javascript const ThemeContext = createContext(); function App() { const [theme, setTheme] = useState("light"); return ( <ThemeContext.Provider value={{ theme, setTheme }}> <Header /> <Footer /> </ThemeContext.Provider> ); } ``` Коли викликається `setTheme("dark")`, `value={{ theme, setTheme }}` стає **новим об'єктом**, і React бачить, що **посилання на value змінилося**, -> **всі компоненти з** `useContext(ThemeContext)` **ререндеряться**. --- ## Чому це важливо React **порівнює не вміст контексту, а посилання** на об'єкт: ```javascript value={{ theme, setTheme }} ``` Кожен рендер створює **новий об'єкт** -> отже, контекст "змінився". --- ## Як зменшити кількість ререндерів Якщо твій контекст зберігає **кілька значень**, але змінюється тільки одне - можна оптимізувати. --- ### 1. Розділи контексти Замість одного великого контексту: ```javascript <AppContext.Provider value={{ user, theme, language }}> ``` розділи їх: ```javascript <UserContext.Provider value={user}> <ThemeContext.Provider value={theme}> <LangContext.Provider value={language}> <App /> </LangContext.Provider> </ThemeContext.Provider> </UserContext.Provider> ``` Тепер зміна теми не викличе ререндер споживачів `UserContext`. --- ### 2. Мемоізуй `value` за допомогою `useMemo` Щоб `Provider` не створював **новий об'єкт** при кожному рендері: ```javascript const value = useMemo(() => ({ theme, setTheme }), [theme]); return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>; ``` Тепер посилання на `value` стабільне - контекст оновиться **тільки при зміні** `theme`, а не при кожному рендері батька. --- ### 3. Розмісти споживачів глибше Якщо контекст використовується тільки в частині UI, розмісти `Provider` **ближче до місця використання**, щоб менше компонентів залежало від нього. --- ## Як думає React React діє за принципом: > "Якщо значення контексту змінилося - > я маю оновити всі компоненти, які його використовують, > щоб вони відображали актуальні дані." Це гарантує **узгодженість UI**, але може створювати **зайві ререндери**, якщо не оптимізувати. --- ## Підсумок | Питання | Відповідь | |---|---| | Чому всі споживачі ререндеряться | Тому що у `Provider.value` змінилося посилання (React вважає, що значення нове) | | Що саме React перевіряє | Не вміст, а посилання (`Object.is(valueOld, valueNew)`) | | Як уникнути | Мемоізувати `value` через `useMemo` або розділити контексти | | Коли це не проблема | Якщо контекст маленький і рідко оновлюється | | Коли потрібно оптимізувати | Якщо одна зміна тригерить рендер десятків компонентів |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.