import React, { useState, useEffect, useRef, useContext, useReducer, useMemo } from 'react';

В представленном React-компоненте LazyInit используется ленивое инициализирование состояния через функцию в useState, что правильно, так как функция someFunc вызывается только один раз при монтировании компонента.

Короткий ответ

Что ответить на собеседовании

В представленном React-компоненте LazyInit используется ленивое инициализирование состояния через функцию в useState, что правильно, так как функция someFunc вызывается только один раз при монтировании компонента.

Подробный разбор

Ответ с пояснениями

Условие

import React, { useState, useEffect, useRef, useContext, useReducer, useMemo } from 'react';

const someFunc = (arr) => { return [...arr].sort((a, b) => a - b); };

const LazyInit = (props) => { const [arr, setArr] = useState(() => someFunc(props.arr));

const onClick = () => { setArr((prev) => prev.concat(prev.length + 1)) }

return ( <> <button onClick={onClick}> Increment {arr.map((n, index) => {n})} </> ) }

export default () => <LazyInit arr={[1, 2, 3]} />;


Обсуждение справа касается:

  • Использования TypeScript с обобщениями: "<T extends object, K extends keyof T>"
  • Проверки, является ли данные строкой, с помощью type guard: "isString(data: unknown): data is string { ... }"
  • Использования useState с функцией для избегания повторного выполнения при каждом рендере:
    const [state, setState] = useState(getComplexData);
    // или
    const [state, setState] = useState(() => getComplexData());
    
  • Функция, передаваемая в useState, выполнится только один раз при монтировании компонента.
  • Предупреждение о мутации состояния напрямую на строке 11 с помощью prev.concat.

Техническое задание — проанализировать и, возможно, исправить или оптимизировать код React-компонента, особенно сосредоточившись на:

  • Правильной ленивой инициализации состояния с помощью useState.
  • Избегании прямой мутации состояния.
  • Понимании обобщений TypeScript и type guards.
  • Обеспечении правильного обновления состояния компонента при клике на кнопку.

Ответ

В представленном React-компоненте LazyInit используется ленивое инициализирование состояния через функцию в useState, что правильно, так как функция someFunc вызывается только один раз при монтировании компонента.

Однако есть важный момент с обновлением состояния в обработчике onClick:

const onClick = () => {
  setArr((prev) => prev.concat(prev.length + 1));
}

Здесь используется метод concat, который не мутирует исходный массив, а возвращает новый — это корректно и не нарушает иммутабельность состояния. Поэтому предупреждение о мутации состояния не обосновано в этом случае.

Если бы использовался метод push, то это была бы мутация, и нужно было бы избегать этого.

Возможные улучшения:

  • Для ключей в списке лучше использовать уникальные значения, а не индекс, чтобы избежать проблем с рендерингом при изменении массива:
{arr.map((n) => <li key={n}>{n}</li>)}
  • Если props.arr может изменяться, а состояние нужно инициализировать заново, стоит добавить эффект useEffect для обновления состояния при изменении пропса.

  • В части TypeScript:

    • Использование дженериков <T extends object, K extends keyof T> позволяет создавать обобщённые функции или компоненты, которые работают с объектами и их ключами, обеспечивая типовую безопасность.
    • Типовой гард isString(data: unknown): data is string помогает уточнять типы в рантайме, что полезно для безопасной работы с данными неизвестного типа.

В целом, компонент корректен, и ленивое инициализирование состояния реализовано правильно.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее