← Назад к вопросам
Какие знаешь триггеры для повторного рендеринга компонента?
1.8 Middle🔥 211 комментариев
#React#Оптимизация и производительность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Триггеры повторного рендеринга в React
Рендеринг в React происходит не просто так. Есть чёткие триггеры, которые заставляют компонент пересчитывать вывод. Понимание этих триггеров критично для оптимизации производительности.
1. Изменение State (Состояния)
Это самый частый триггер:
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
{/* При клике → изменится state → рендер! */}
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}
// Триггер: setCount() изменит состояние
// Результат: компонент ре-рендерится
2. Изменение Props (Пропсов)
Когда родитель передаёт новые props, компонент ре-рендерится:
function Parent() {
const [name, setName] = useState('John');
return (
<div>
<Child name={name} />
<button onClick={() => setName('Jane')}>Change</button>
</div>
);
}
function Child({ name }) {
// При изменении name → ре-рендер!
return <p>Hello, {name}</p>;
}
// Триггер: новый props name
// Результат: Child ре-рендерится
3. Контекст (Context)
Изменение контекста вызывает ре-рендер всех подписанных компонентов:
const ThemeContext = createContext();
function App() {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={theme}>
<Header />
<Main />
<Footer />
<button onClick={() => setTheme('dark')}>Toggle</button>
</ThemeContext.Provider>
);
}
function Header() {
const theme = useContext(ThemeContext);
// При изменении theme → ре-рендер Header!
return <h1 style={{ color: theme === 'dark' ? 'white' : 'black' }}>Header</h1>;
}
4. Ре-рендер родителя
Когда родитель ре-рендерится, все дети ре-рендерятся (по умолчанию):
function Parent() {
const [count, setCount] = useState(0);
return (
<div>
<p>Parent count: {count}</p>
{/* Child ре-рендерится вместе с Parent! */}
<Child message="Hello" />
<button onClick={() => setCount(count + 1)}>Parent +</button>
</div>
);
}
function Child({ message }) {
// Ре-рендерится каждый раз, когда Parent ре-рендерится
// Даже если message не изменился!
console.log('Child rendered');
return <p>{message}</p>;
}
5. Reducers (Redux, useReducer)
Диспатч action также вызывает ре-рендер:
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div>
<p>Count: {state.count}</p>
{/* dispatch() → ре-рендер */}
<button onClick={() => dispatch({ type: 'INCREMENT' })}>+</button>
</div>
);
}
function reducer(state, action) {
if (action.type === 'INCREMENT') {
return { count: state.count + 1 };
}
return state;
}
6. Ключи в списках (Key prop)
Когда изменяется список (добавление/удаление элементов), ключи определяют, какие компоненты ре-рендерятся:
function TodoList() {
const [todos, setTodos] = useState([]);
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.text}</li> {/* key очень важен! */}
))}
<button onClick={() => {
setTodos([...todos, { id: Date.now(), text: 'New' }]);
}}>Add</button>
</ul>
);
}
7. Свойства в объектах/массивах
Изменение свойств в объектах или массивах:
function Profile() {
const [user, setUser] = useState({ name: 'John', age: 30 });
// Это ВСЕ вызывают ре-рендер:
const updateName = () => {
setUser({ ...user, name: 'Jane' }); // ре-рендер
};
const updateAge = () => {
setUser({ ...user, age: 31 }); // ре-рендер
};
return (
<div>
<p>{user.name}, {user.age}</p>
<button onClick={updateName}>Change name</button>
<button onClick={updateAge}>Change age</button>
</div>
);
}
Оптимизация: Предотвращение лишних рендеров
1. React.memo (для функциональных компонентов)
const Child = React.memo(({ name }) => {
console.log('Child rendered');
return <p>Hello, {name}</p>;
});
function Parent() {
const [count, setCount] = useState(0);
return (
<div>
<Child name="John" />
<button onClick={() => setCount(count + 1)}>+</button>
{/* Child НЕ ре-рендерится, если props не изменились */}
</div>
);
}
2. useMemo (мемоизация значений)
function Parent() {
const [count, setCount] = useState(0);
const [filter, setFilter] = useState('');
// Пересчитывается только если filter изменился
const filteredItems = useMemo(() => {
console.log('Computing...');
return items.filter(item => item.name.includes(filter));
}, [filter]);
return (
<div>
<p>Count: {count}</p>
<Child items={filteredItems} />
<button onClick={() => setCount(count + 1)}>Parent +</button>
</div>
);
}
3. useCallback (мемоизация функций)
function Parent() {
const [count, setCount] = useState(0);
// Функция создаётся один раз
const handleClick = useCallback(() => {
console.log('Clicked');
}, []); // deps empty
return (
<div>
{/* Child не ре-рендерится, так как handleClick не изменилась */}
<Child onClick={handleClick} />
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}
4. Рефакторинг: Поднять state выше
// ❌ Плохо: Child ре-рендерится каждый раз
function Parent() {
const [count, setCount] = useState(0);
return (
<div>
<Child message="Static" /> {/* ре-рендерится! */}
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}
// ✅ Хорошо: разделить компоненты
function Parent() {
const [count, setCount] = useState(0);
return (
<div>
<StaticChild />
<Counter />
</div>
);
}
5. Состояние в локальном элементе
// ❌ Плохо: state в родителе → все дети ре-рендерятся
function Parent() {
const [localState, setLocalState] = useState('');
return (
<div>
<input value={localState} onChange={(e) => setLocalState(e.target.value)} />
<Child /> {/* ре-рендерится каждый раз! */}
</div>
);
}
// ✅ Хорошо: state в отдельном компоненте
function InputComponent() {
const [localState, setLocalState] = useState('');
return <input value={localState} onChange={(e) => setLocalState(e.target.value)} />;
}
function Parent() {
return (
<div>
<InputComponent />
<Child /> {/* не ре-рендерится */}
</div>
);
}
Инструменты для отладки
// React DevTools Profiler:
// 1. Откроем React DevTools
// 2. Перейдём на вкладку "Profiler"
// 3. Кликнули Record
// 4. Взаимодействовали с компонентом
// 5. Остановили запись
// Увидим все ре-рендеры с причинами
// Или логируем вручную:
import { useWhyDidYouUpdate } from '@react-hookz/web';
function MyComponent(props) {
useWhyDidYouUpdate('MyComponent', props);
return <div>{props.name}</div>;
}
Ключевые выводы
Триггеры ре-рендера:
- Изменение state
- Изменение props
- Изменение контекста
- Ре-рендер родителя
- Dispatch reducer actions
- Изменение элементов в списках
Оптимизация:
- React.memo для предотвращения ре-рендеров
- useMemo и useCallback для мемоизации
- Правильная структура компонентов
- Избегание создания новых объектов в render
- Использование правильных ключей в списках