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

Прямо сейчас Typescript и React и две самые популярные технологии в веб-разработке. В этой статье мы рассмотрим использование двух технологий в тандеме, охватывая базовую проверку типов в функциональных компонентах и ​​компонентах классов. Статья предназначена для всех, кто впервые объединяет TypeScript и React, но она также должна быть полезна для тех, кому нужно быстрое напоминание о синтаксисе.

Что такое React?

React (поддерживается Facebook) - декларативная компонентная библиотека. Он упрощает создание интерактивных компонентов многократного использования, которые благодаря своей виртуальной модели DOM обновляются высокоэффективно.

Что такое машинописный текст?

TypeScript (созданный Microsoft) - это надмножество JavaScript: он содержит все функции JavaScript, а также множество функций проверки типов, напоминающих языки со строгой типизацией, такие как Java и C #. Это упрощает чтение, понимание и отладку кода.

Создание проекта React-TypeScript

Самый простой способ начать работу с обеими технологиями - использовать пакет create-react-app плюс --template typescript. Выберите npx или yarn и запустите:

# npx
npx create-react-app app-name --template typescript
# yarn
yarn create react-app app-name --template typescript

Создание простого счетчика

Чтобы охватить основные варианты использования Typescript в React, мы создадим базовый компонент Counter. Во-первых, мы будем использовать компонент класса. Затем мы создадим идентичную функцию с функциональным компонентом и хуками.

Чтобы продолжить, создайте папку components внутри src и добавьте в нее ClassCounter.tsx и FunctionalCounter.tsx:

cd src && mkdir components && cd components && touch ClassCounter.tsx && touch FunctionalCounter.tsx

В следующем разделе мы по очереди рассмотрим классовый и функциональный варианты и обсудим ключевые различия.

На нашем счетчике будет две кнопки: одна с плюсом, а другая с минусом, и мы решаем, добавлять или вычитать, исходя из innerText нажатой кнопки. (Конечно, мы могли бы просто использовать отдельные функции increment и decrement, но я хотел показать вам, как проверять типы событий!)

Версия компонента класса

import React, { PureComponent } from "react";
class ClassCounter extends PureComponent<{}, { count: number }> {
  state = { count: 0 };
  updateCount = (e: React.MouseEvent<HTMLButtonElement>): void => {
    switch (e.currentTarget.innerText) {
      case "-":
        this.setState({ count: this.state.count - 1 });
        break;
      case "+":
      default:
        this.setState({ count: this.state.count + 1 });
        break;
    }
  };
  render(): JSX.Element {
    const { count } = this.state;
    return (
      <div>
        <h2>Class Component</h2>
        <h1>{count}</h1>
        <button onClick={this.updateCount}>+</button>
        <button onClick={this.updateCount}>-</button>
      </div>
    );
  }
}
export default ClassCounter;

Поскольку наш счетчик включает в себя изменение простого типа (единственное значение, содержащееся в состоянии, - это число), мы можем использовать PureComponent, а не Component, поскольку это выполняет только поверхностное сравнение.

Мы набираем "check the props" и "состояние" сразу после PureComponent. Поскольку никаких реквизитов нет, он представлен как пустой объект {}, а состояние - { count: number }.

Следующий пример проверки типа происходит в нашем методе updateCount. Нам нужно получить доступ к объекту события, переданному щелчком мыши. Поскольку React переопределяет нативный MouseEvent, мы используем React.MouseEvent, а затем указываем тип элемента в угловых скобках: в данном случае <HTMLButtonElement>. Поскольку эта функция ничего не возвращает, мы устанавливаем тип возвращаемого значения void.

Наконец, метод рендеринга возвращает JSX.Element.

Версия функционального компонента

import React, { FC, useState, useCallback } from "react";
const FunctionalCounter: FC<{}> = (): JSX.Element => {
  const [count, setCount] = useState(0);
  const updateCount = useCallback(
    (e: React.MouseEvent<HTMLButtonElement>): void => {
      switch (e.currentTarget.innerText) {
        case "-":
          setCount(count - 1);
          break;
        case "+":
        default:
          setCount(count + 1);
          break;
      }
    },
    [count]
  );
  return (
    <div>
      <h2>Functional Component</h2>
      <h1>{count}</h1>
      <button onClick={updateCount}>+</button>
      <button onClick={updateCount}>-</button>
    </div>
  );
};
export default FunctionalCounter;

При использовании функциональных компонентов с TypeScript вам потребуется импортировать FC интерфейс из React. За ним следует тип props в угловых скобках, но поскольку у нас нет props, мы будем использовать пустой объект {}. Тип возврата - JSX.Element.

Одно из основных отличий версии функционального компонента заключается в том, что нам не нужно вводить состояние. Это потому, что тип предполагается из любого аргумента, указанного в useState - в данном случае 0, number.

Наша функция updateCount практически идентична методу updateCount в нашем компоненте класса, за исключением того, что на этот раз она заключена внутри useCallback. Это дает те же преимущества, что и PureComponent. Это «запомнит» обратный вызов, а это означает, что он изменится только в случае изменения одной из зависимостей, предотвращая ненужные повторные отрисовки. Эти зависимости указаны во втором аргументе useCallback.

Добавление реквизита

До сих пор мы рассмотрели основной синтаксис проверки типов, с которым вы столкнетесь при использовании TypeScript с React. Но есть часть нашего дизайна, которую можно улучшить. В настоящий момент мы полагаемся на innerText наших кнопок, чтобы определить, увеличивать или уменьшать наш счетчик. Но innerText может быть чем угодно. Что, если другой разработчик захочет заменить innerText словом «плюс» или использовать символ? Тогда наша функция сломается!

Машинопись может помочь предотвратить это. Для этого давайте создадим новый Button компонент, который принимает либо "+", либо "-".

Версия компонента класса

Сначала мы определим новый тип type ButtonType = "+" | "-". Затем мы создадим Button компонент, который принимает type prop и updateCount prop, оба из которых указаны в угловых скобках.

type ButtonType = "+" | "-";
class Button extends PureComponent<
  { type: ButtonType; updateCount: (type: ButtonType) => void },
  {}
> {
  render(): JSX.Element {
    const { type, updateCount } = this.props;
    return <button onClick={() => updateCount(type)}>{type}</button>;
  }
}

Затем в нашем компоненте счетчика классов мы можем заменить старые элементы <button> на следующие:

<Button updateCount={this.updateCount} type="+" />
<Button updateCount={this.updateCount} type="-" />

Теперь, если разработчик попытается передать что-либо, кроме "+" или "-" одной из кнопок, TypeScript выдаст ошибку.

Версия функционального компонента (без сохранения состояния)

На мой взгляд, функциональный вариант компонента Button демонстрирует, что функциональные компоненты без сохранения состояния часто легче читать - в таких простых случаях, как этот - чем классы:

type ButtonType = "+" | "-";
const Button = ({
  type,
  updateCount,
}: {
  type: ButtonType;
  updateCount: (type: ButtonType) => void;
}): JSX.Element => 
  <button onClick={() => updateCount(type)}>{type}</button>;

Как теперь сказано, нам не нужно указывать FC, как это делается в компоненте FunctionalCounter. В этом компоненте мы теперь можем заменить элементы <button> на следующие:

<Button updateCount={updateCount} type="+" />
<Button updateCount={updateCount} type="-" />

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