JavaRush /Курсы /Модуль 3: React /Типизация компонентов для оптимизации рендеринга

Типизация компонентов для оптимизации рендеринга

Модуль 3: React
10 уровень , 2 лекция
Открыта

Стратегии типизации компонентов

Теперь пора посмотреть, как правильная типизация компонентов может помочь нам сократить лишние рендеры и улучшить читаемость и поддержку кода.

Давайте начнем с практики. У нас есть три основные сущности для типизации в React:

  1. Props — данные, которые компонент принимает извне.
  2. State — внутреннее состояние компонента.
  3. Return type — результат работы компонента.

На практике, правильная типизация этих сущностей позволяет нам строить производительный и надёжный код.

Типизация props

Начнем с самого простого сценария. Допустим, у нас есть компонент, который отображает информацию о пользователе.

import React from "react";

// Определяем интерфейс для props
interface UserInfoProps {
  name: string;
  age: number;
}

// Компонент типизируется пропсами
const UserInfo: React.FC<UserInfoProps> = ({ name, age }) => {
  return (
    <div>
      <h3>{name}</h3>
      <p>Возраст: {age}</p>
    </div>
  );
};

// Пример использования
<UserInfo name="Иван" age={30} />

⚡ Обратите внимание: мы используем React.FC (функциональный компонент) для типизации. Он автоматически добавляет типы для children, что очень удобно.

Но бывает, что нам нужно указать пропсы опциональными. В таком случае просто добавляем ?:

interface UserInfoProps {
  name: string;
  age?: number; // Этот пропс теперь необязательный
}

const UserInfo: React.FC<UserInfoProps> = ({ name, age }) => {
  return (
    <div>
      <h3>{name}</h3>
      <p>Возраст: {age || "Не указан"}</p>
    </div>
  );
};

Типизация состояния (state)

Теперь представим, что у нас есть компонент с состоянием. Например, компонент счётчика.

import React, { useState } from "react";

// Определяем интерфейс для состояния
interface CounterState {
  count: number;
}

const Counter: React.FC = () => {
  // useState типизируется явно
  const [state, setState] = useState<CounterState>({ count: 0 });

  const increment = () => setState({ count: state.count + 1 });

  return (
    <div>
      <p>Счётчик: {state.count}</p>
      <button onClick={increment}>+</button>
    </div>
  );
};

Если наше состояние было бы более сложным (например, вложенные объекты), мы также могли бы вынести его описание в отдельный интерфейс.

Типизация return type

В большинстве случаев TypeScript сам способен определить тип возвращаемого значения функции. Однако иногда, например, при использовании HOC, явное указание типа может быть полезным.

const Button: React.FC<{ label: string }> = ({ label }) => {
  return <button>{label}</button>;
};

const withLoading =
  <P extends object>(Component: React.ComponentType<P>) =>
  (props: P & { isLoading: boolean }) => {
    if (props.isLoading) {
      return <p>Загрузка...</p>;
    }
    return <Component {...props} />;
  };

const WrappedButton = withLoading(Button);
<WrappedButton label="Клик!" isLoading={false} />;

Как типизация помогает оптимизировать рендеринг

Оптимизация с мемоизацией

Когда мы используем такие инструменты, как React.memo, типизация играет ключевую роль в проверке входных данных. Взгляните на пример:

import React from "react";

interface DataViewProps {
  data: string[];
}

const DataView: React.FC<DataViewProps> = React.memo(({ data }) => {
  console.log("Ререндер компонента");
  return (
    <ul>
      {data.map((item, index) => (
        <li key={index}>{item}</li>
      ))}
    </ul>
  );
});

const ParentComponent: React.FC = () => {
  const data = ["React", "TypeScript", "Optimization"];

  return <DataView data={data} />;
};

Благодаря React.memo, компонент DataView не ререндерится, если data не изменяется. А типизация позволяет нам быть на 100% уверенными, что формат данных корректный!

Типизация зависимостей в хуках

Типизация становится особенно полезной, когда мы используем хуки вроде useCallback или useMemo.

import React, { useCallback } from "react";

interface ButtonProps {
  onClick: () => void;
}

const Button: React.FC<ButtonProps> = ({ onClick }) => {
  return <button onClick={onClick}>Клик!</button>;
};

const ParentComponent: React.FC = () => {
  const handleClick = useCallback(() => {
    console.log("Кнопка нажата!");
  }, []); // Типизация обеспечит правильные зависимости!

  return <Button onClick={handleClick} />;
};

Типизация в ленивых компонентах (React.lazy)

Когда мы загружаем компоненты динамически, важно быть уверенными в их типизации. React и TypeScript заставляют нас быть немного аккуратнее:

import React, { lazy, Suspense } from "react";

// Динамически загружаемый компонент
const LazyComponent = lazy(() => import("./LazyComponent"));

const App: React.FC = () => {
  return (
    <Suspense fallback={<div>Загрузка...</div>}>
      <LazyComponent />
    </Suspense>
);
};

Для проверки типов импортируемого компонента мы можем использовать assertion:

const LazyComponent = lazy(() =>
  import("./LazyComponent").then((module) => ({
    default: module.LazyComponent as React.ComponentType<{ propA: string }>,
  }))
);

Теперь любой неправильный пропс для LazyComponent будет выявлен на этапе компиляции.

Подводные камни типизации

Хотя типизация очень помогает, бывают ситуации, где нужно быть осторожным:

  1. Слишком сложные типы: если вы чувствуете, что пишете больше типов, чем кода, стоит упростить.
  2. Опциональные пропсы: не забывайте задавать значения по умолчанию через defaultProps или в функции.
  3. Перекрестные зависимости: типы, завязанные друг на друга, могут вызывать головную боль.

Код, который мы построили сегодня, — не только способ избежать багов и головной боли, но и возможность заставить ваше приложение работать быстрее и надёжнее. Впереди нас ждут ещё более сложные механики оптимизации.

1
Задача
Модуль 3: React, 10 уровень, 2 лекция
Недоступна
Типизация состояния в компоненте
Типизация состояния в компоненте
1
Задача
Модуль 3: React, 10 уровень, 2 лекция
Недоступна
Оптимизация и типизация мемоизированного компонента
Оптимизация и типизация мемоизированного компонента
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Вероника Уровень 83
9 декабря 2025
Задачу 1 невозможно решить.