Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Чому компонент, оголошений усередині іншого компонента, губить стан і повільно працює?

React вирішує, чи зберегти компонент між рендерами, за двома ознаками: позиція в дереві і тип (функція-компонент). Якщо на тій самій позиції опинився інший тип - старий компонент знищується разом зі станом і DOM, новий створюється з нуля.

Типова помилка:

function VacancyPage({ vacancy }) {
  const [tab, setTab] = useState('description');

  // нова функція на КОЖНОМУ рендері VacancyPage
  function ApplyForm() {
    const [email, setEmail] = useState('');
    return <input value={email} onChange={(e) => setEmail(e.target.value)} />;
  }

  return (
    <>
      <Tabs value={tab} onChange={setTab} />
      <ApplyForm />
    </>
  );
}

Кожен рендер VacancyPage створює нову функцію ApplyForm - для React це новий тип компонента. Наслідки:

  • стан скидається: введений email зникає при перемиканні вкладки;
  • DOM перестворюється - втрачається фокус, позиція курсору, анімації;
  • дорожче: монтування з нуля замість оновлення.

Рішення: оголошувати компоненти на верхньому рівні модуля і передавати дані через props. Правило static-components з eslint-plugin-react-hooks ловить цю помилку автоматично.

Та сама механіка свідомо - key для скидання стану:

<ProfileForm key={userId} user={user} />

Зміна key - новий компонент: форма скидається при переході до іншого користувача. Це краще, ніж синхронізувати стан з props в ефекті.

Але key має ціну. Перемонтування - це знищення й створення всього піддерева: ефекти очищення й запуску, нові запити, втрата стану в усіх нащадках. Зміна key на великому дереві без потреби (наприклад, key={Math.random()} чи key={JSON.stringify(filters)} на всій сторінці) - джерело повільності й «миготіння».

Інші випадки втрати стану через позицію:

  • умовний рендер, що змінює структуру: {isEditing ? <Form /> : <Preview />} на тій самій позиції - стан форми зникає при перемиканні. Якщо стан треба зберегти - тримати його вище чи ховати компонент CSS;
  • різні обгортки: <div><Counter /></div> проти <section><Counter /></section> - інший тип батька, лічильник скидається;
  • індекс у key списку - при видаленні першого елемента стан «переїжджає» на сусідні.

Правило: тип і позиція компонента мають бути стабільними, а скидання стану - явним, через key.

Докладніше в документації: Збереження й скидання стану

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання