← Назад к вопросам

В каких случаях компонент будет перерисовываться

2.0 Middle🔥 281 комментариев
#React#State Management#Оптимизация и производительность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

В каких случаях компонент будет перерисовываться

Перерисовка (re-render) компонента в React происходит когда нужно обновить DOM на основе изменений в состоянии, пропсах или контексте. Понимание причин перерисовки критично для оптимизации производительности приложения.

Основные причины перерисовки

1. Изменение state

Это самая частая причина:

function Counter() {
  const [count, setCount] = useState(0);
  
  // Компонент перерисуется когда setCount вызовет изменение count
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  );
}

Каждый вызов setCount с НОВЫМ значением = перерисовка.

2. Изменение props

function Child({ name }) {
  console.log('Child перерисовалась');
  return <div>Hello, {name}!</div>;
}

function Parent() {
  const [user, setUser] = useState('Alice');
  
  // Каждое изменение user → Child перерисуется
  return <Child name={user} />;
}

3. Изменение Context

const ThemeContext = createContext();

function App() {
  const [theme, setTheme] = useState('light');
  
  // Все потребители контекста перерисуются когда изменится value
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <Header />
      <Content />
      <Footer />
    </ThemeContext.Provider>
  );
}

4. Родитель перерисовался

Важный момент: если родитель перерисовался, все его дети также перерисуются по умолчанию!

function Parent() {
  const [counter, setCounter] = useState(0);
  
  return (
    <div>
      <p>Count: {counter}</p>
      <button onClick={() => setCounter(counter + 1)}>+1</button>
      {/* Child перерисуется ДА ЖЕ если его props не изменились! */}
      <Child name="Bob" />
    </div>
  );
}

function Child({ name }) {
  console.log('Child перерисовалась'); // Логирует каждый раз
  return <div>{name}</div>;
}

Оптимизация перерисовок

1. React.memo

Предотвращает перерисовку если props не изменились:

const Child = React.memo(({ name }) => {
  console.log('Child перерисовалась');
  return <div>{name}</div>;
});

function Parent() {
  const [counter, setCounter] = useState(0);
  
  return (
    <div>
      <p>Count: {counter}</p>
      <button onClick={() => setCounter(counter + 1)}>+1</button>
      {/* Child НЕ будет перерисована при клике */}
      <Child name="Bob" />
    </div>
  );
}

2. useMemo

Мемоизирует вычисленное значение:

function Parent() {
  const [counter, setCounter] = useState(0);
  const [text, setText] = useState('');
  
  // expensiveValue пересчитывается только когда counter изменяется
  const expensiveValue = useMemo(() => {
    console.log('Дорогое вычисление');
    return counter * 2;
  }, [counter]); // зависимость: counter
  
  return (
    <div>
      <input value={text} onChange={(e) => setText(e.target.value)} />
      <p>Expensive: {expensiveValue}</p>
      {/* Child только если expensiveValue изменилась */}
      <Child value={expensiveValue} />
    </div>
  );
}

3. useCallback

Мемоизирует функцию для передачи в пропсы:

const ChildWithButton = React.memo(({ onClick }) => {
  console.log('ChildWithButton перерисовалась');
  return <button onClick={onClick}>Click</button>;
});

function Parent() {
  const [counter, setCounter] = useState(0);
  
  // ❌ Без useCallback — функция пересоздаётся, Child перерисуется
  const handleClick = () => console.log(counter);
  
  // ✅ С useCallback — функция мемоизирована
  const handleClick = useCallback(() => {
    console.log(counter);
  }, [counter]); // зависимость: counter
  
  return (
    <div>
      <p>Count: {counter}</p>
      <button onClick={() => setCounter(counter + 1)}>+1</button>
      {/* Child не перерисуется если counter не в зависимостях */}
      <ChildWithButton onClick={handleClick} />
    </div>
  );
}

4. Правильная структура state

// ❌ Плохо: единый большой state вызывает перерисовку всего
function App() {
  const [data, setData] = useState({ user: {}, posts: [], settings: {} });
  
  return (
    <>
      <User data={data.user} />
      <Posts data={data.posts} />
      <Settings data={data.settings} />
    </>
  );
}

// ✅ Хорошо: разделить state или использовать Context
function App() {
  const [user, setUser] = useState({});
  const [posts, setPosts] = useState([]);
  const [settings, setSettings] = useState({});
  
  return (
    <>
      <User data={user} />
      <Posts data={posts} />
      <Settings data={settings} />
    </>
  );
}

Пример: Все причины в одном компоненте

function ComplexExample() {
  const [count, setCount] = useState(0);        // Причина 1: state
  const theme = useContext(ThemeContext);       // Причина 3: context
  
  // Причина 4: если родитель перерисовался, этот тоже перерисуется
  console.log('ComplexExample перерисовалась');
  
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
      {/* Причина 2: Child перерисуется если theme изменится */}
      <Child theme={theme} />
    </div>
  );
}

Как отследить перерисовки

1. Используй console.log

function MyComponent() {
  console.log('MyComponent перерисовалась');
  return <div>Content</div>;
}

2. DevTools Profiler (React)

  • Открыть React DevTools
  • Вкладка "Profiler"
  • Кнопка "Record"
  • Взаимодействовать с приложением
  • Видеть какие компоненты перерисовались и почему

3. Highlight updated components

В React DevTools:

  • Settings → Highlight updates when components render
  • Обновляемые компоненты будут подсвечиваться

Важные правила

DO:

  • Используй useState для локального состояния
  • Мемоизируй дорогие вычисления с useMemo
  • Мемоизируй callback функции с useCallback
  • Используй React.memo для чистых компонентов

DON'T:

  • Не создавай новые объекты/массивы в каждом рендере
  • Не передавай inline функции как пропсы
  • Не используй Context для часто меняющихся данных (используй Redux/Zustand)

Перерисовка в Next.js

В Next.js с Server Components дополнительно:

// Server Component — не перерисуется вообще
export default async function ServerComponent() {
  const data = await fetchData();
  return <div>{data}</div>;
}

// Client Component — перерисуется когда state/props изменятся
'use client';
export default function ClientComponent() {
  const [data, setData] = useState(null);
  return <div>{data}</div>;
}

Четыре главных причины перерисовки: изменение state, props, context, или перерисовка родителя. Оптимизация требует понимания этих механизмов!

В каких случаях компонент будет перерисовываться | PrepBro