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

Навіщо передавати функцію в useState замість обчисленого початкового значення?

Початкове значення useState використовується лише при першому рендері. Але вираз, переданий аргументом, обчислюється на кожному рендері - бо це звичайний виклик функції компонента.

function Editor() {
  // parseDraft викликається на КОЖНОМУ рендері, хоча результат потрібен один раз
  const [draft, setDraft] = useState(parseDraft(localStorage.getItem('draft')));
  // ...
}

Якщо обчислення дороге (розбір великого JSON, читання localStorage, побудова структури з тисяч елементів), компонент сповільнюється на кожне введення в поле.

Лінива ініціалізація - передати функцію, а не її результат:

const [draft, setDraft] = useState(() => parseDraft(localStorage.getItem('draft')));

React викличе функцію лише при першому рендері. Зверніть увагу на різницю:

useState(createInitialTodos());   // викликається щоразу
useState(createInitialTodos);     // передано саму функцію - лише раз
useState(() => createInitialTodos(userId));   // з аргументом - через обгортку

Те саме для useReducer - третій аргумент-ініціалізатор:

const [state, dispatch] = useReducer(reducer, userId, createInitialState);

Для useRef вбудованої лінивої ініціалізації немає - роблять вручну:

const playerRef = useRef<VideoPlayer | null>(null);
if (playerRef.current === null) {
  playerRef.current = new VideoPlayer();   // створюється один раз
}

Що варто знати:

  • у StrictMode функція-ініціалізатор у режимі розробки викликається двічі - вона має бути чистою (без запитів, підписок, побічних ефектів);
  • для дешевих значень (useState(0), useState([]), useState(props.initial)) лінива ініціалізація не потрібна - виграшу немає;
  • ініціалізація з props відбувається один раз: useState(props.value) не оновиться, коли props.value зміниться. Якщо значення має стежити за props, стан не потрібен - обчислюйте під час рендеру, а для «скидання» стану використайте key.

Докладніше в документації: useState: уникнення повторного створення початкового стану

Перевір себе

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

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