Рішення про перерисовку компонента
Коротка відповідь
React перерисовує компонент (re-render), коли:
- Змінюється його стан (
state) - Змінюються його властивості (
props) - Змінюється контекст (
context), якщо він використовується в компоненті - Його батько був перерендерений, і передав йому нові props (або навіть ті самі, але без оптимізації)
1. Зміна state
Якщо в компоненті викликається setState (або setCount, setUser тощо), React запускає повторний рендер цього компонента.
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
{count}
</button>
);
}Кожен виклик setCount() -> React створює нове Virtual DOM дерево для цього компонента і порівнює його з попереднім (diffing).
2. Зміна props
Якщо батьківський компонент передає нові props,
React перерендерює дочірній компонент, щоб відобразити оновлені дані.
function Greeting({ name }) {
return <h1>Привіт, {name}!</h1>;
}
function App() {
const [name, setName] = useState("Alex");
return <Greeting name={name} />;
}Коли setName("Maria") -> React перерендерить App,
а потім і Greeting, тому що його props.name змінилися.
3. Зміна контексту (useContext)
Якщо компонент підписаний на контекст через useContext,
він перерисується при зміні значення контексту.
const ThemeContext = createContext("light");
function Button() {
const theme = useContext(ThemeContext);
return <button className={theme}>Click</button>;
}
function App() {
const [theme, setTheme] = useState("light");
return (
<ThemeContext.Provider value={theme}>
<Button />
</ThemeContext.Provider>
);
}setTheme("dark") -> усі компоненти, що використовують цей контекст, перерисуються.
4. Коли батько перерендерився
Навіть якщо props не змінилися за значенням,
React все одно типово перерендерить дочірній компонент,
якщо батько був перерендерений.
function Child() {
console.log("Child render");
return <p>Дитина</p>;
}
function Parent() {
const [count, setCount] = useState(0);
return (
<>
<button onClick={() => setCount(count + 1)}>+</button>
<Child />
</>
);
}Кожен клік -> Parent оновлюється ->
Child теж перерендериться, хоча в нього немає ні state, ні props.
Щоб цього уникнути, можна обгорнути Child в:
export default React.memo(Child);Тепер React буде ререндерити Child лише якщо змінилися його props.
Що не викликає ререндер
Зміна змінних поза state
let count = 0;
function Counter() {
count++;
// React не знає про count - вона не з state
}Зміна об'єкта "повз" setState
state.user.name = "Maria"; // React це не відстежитьПряма зміна DOM (document.querySelector)
React керує своїм Virtual DOM - він не стежить за ручними змінами реального DOM.
Як React вирішує, що саме оновити
Після того як React вирішує, що компонент має бути перерендерений:
- Він знову викликає функцію компонента (щоб отримати новий JSX).
- Створює нове Virtual DOM-дерево.
- Порівнює його з попереднім (diffing).
- Змінює лише те, що реально змінилося в реальному DOM (reconciliation).
Оптимізація: коли не потрібно перерендерювати
Використовуй React.memo() для функціональних компонентів:
перерендериться лише при зміні props.
Використовуй useMemo() і useCallback(),
щоб не пересоздавати функції та обчислення даремно.
Передавай стабільні значення (id, name тощо), а не нові об'єкти/функції при кожному рендері.
Підсумок
| Причина | Компонент перерендериться? |
|---|---|
Змінився state | Так |
Змінилися props | Так |
| Змінився контекст | Так |
| Батько перерендерився | Так (якщо не React.memo) |
Змінилася змінна поза state | Ні |
| Пряма зміна DOM | Ні |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.