使用 Typescript 进行反应

2025-05-25

使用 Typescript 进行反应

目前,React.js 已经成为构建美观且可扩展的用户界面的热门库。今天,我想用 TypeScript 构建一个 React 的演示项目。

项目设置

我们希望使用create-react-appFacebook 开发者团队构建的环境来创建我们的项目。我们的项目将包含一个表单,用于添加喜爱的电视剧并显示列表。它将是一个单页网站。首先,我们将运行以下命令:



npx create-react-app --template typescript fav-tv-series
cd fav-tv-series
npm run start


Enter fullscreen mode Exit fullscreen mode

第一个命令会创建一个名为“ fav-tv-serieswith TypeScript Template”的 React 应用。然后,进入该目录后,运行第三个命令,创建一个在 3000 端口上运行的进程,如下所示:
替代文本

创建界面

在 TypeScript 中,我们主要关注的是为每个将要使用的数据定义严格的类型。interface这是一种定义数据并将其用作 ts 类型的好方法。在src根文件夹的文件夹中,我们将创建一个名为 的目录interfaces,并在其中创建一个名为 的文件SeriesProps.tsx。在这里,我们将创建一个名为 的接口,SeriesProps如下所示



export interface SeriesProps {
    seriesList: {
        name: string;
        imdb: number;
        cover: string;
        seasons: number;
        genre: string;
      }[]
}


Enter fullscreen mode Exit fullscreen mode

更新应用程序

首先,我们将App.tsx通过删除现有代码来更新现有文件。我们的单页 Web 应用程序将包含两个组件。一个是表单,用户可以在其中输入关于自己喜欢的系列的必要信息;另一个是包含这些系列的列表。数据将存储在名为 state 的状态中seriesList,并借助setSeriesList方法进行更新。



import React, { useState } from 'react';
import { SeriesProps } from './interfaces/SeriesProps';
import './App.css';
import List from './components/List';
import Form from './components/Form';

function App() {
  const [seriesList, setSeriesList] = useState<SeriesProps["seriesList"]>([]);

  return (
    <div className="App">
      <h1>My Favourite TV Series</h1>
      <Form seriesList={seriesList} setSeriesList={setSeriesList} />
      <List seriesList={seriesList} />
    </div>
  );
}

export default App;



Enter fullscreen mode Exit fullscreen mode

创建列表

在根文件夹的目录中,src我们将创建一个名为的目录components,并在那里创建List.tsx文件。我们的组件如下所示。



import React, { FC } from "react";
import { SeriesProps } from "../interfaces/SeriesProps";

const List:FC<SeriesProps> = ({seriesList}) => (
    <div className="series-list">
        {seriesList.map((series) => (
            <div className="series-item">
                <img src={series.cover} alt="Series-cover" />
                <p><b>{series.name}</b></p>
                <p>{series.genre}</p> 
                <p>{series.seasons} seasons</p>
                <p>★★★★★ {series.imdb}</p>
            </div>
        ))}
    </div>
);

export default List;


Enter fullscreen mode Exit fullscreen mode

这里我们来看一下FC函数式组件,它指导我们如何使用类型。这里我们传入了SeriesPropsprops,最后使用了map函数来渲染电视剧列表。

创建表单

现在我们只需创建表单元素,用于提供必要的输入。这里我们将使用受控组件来构建输入元素。为了简单起见,我们将创建一个状态对象,用于保存必要的输入值。我们将使用useState它来实现这一点。



const [input, setInput] = useState({
        name: "",
        genre: "",
        cover: "",
        imdb: 0,
        seasons: 0
    });


Enter fullscreen mode Exit fullscreen mode

现在我们将渲染组件。这里我们将有五个输入字段,其中三个是文本,两个是数字。



return (
        <div className="form-container">
            <div className="form-div">
                <label htmlFor="name">Name</label>
                <input type="text" name="name" id="name" value={input.name} onChange={handleChange} />
            </div>
            <div className="form-div">
                <label htmlFor="genre">Genre</label>
                <input type="text" name="genre" id="genre" value={input.genre} onChange={handleChange} />
            </div>
            <div className="form-div">
                <label htmlFor="cover">Cover Link</label>
                <input type="text" name="cover" id="cover" value={input.cover} onChange={handleChange} />
            </div>
            <div className="form-div">
                <label htmlFor="imdb">IMDB Rating</label>
                <input type="number" name="imdb" id="imdb" value={input.imdb} onChange={handleChange} />
            </div>
            <div className="form-div">
                <label htmlFor="seasons">Total Seasons</label>
                <input type="number" name="seasons" id="seasons" value={input.seasons} onChange={handleChange} />
            </div>
            <button type="button" onClick={handleClick}>Add Series</button>
        </div>
    );


Enter fullscreen mode Exit fullscreen mode

在这里我们可以看到每个输入字段的值都将存储到状态对象中。我们可以看到所有输入字段都有一个名为的函数,handleChange该函数将作为侦听器调用onChange,并且按钮有一个onClick名为的侦听器handleClick。我们现在将实现这两​​种方法。handleChange 方法非常简单。在这里,我们解构状态input并更新需要更新的特定状态元素。需要注意的一件重要事情是我们传递给该函数的事件类型。这里的类型是,ChangeEvent<HTMLInputElement>这意味着我们的 handleChange 方法将只接受 html 输入元素更改事件。需要注意的一件事是,我们保留了每个输入的名称和值相同,我们可以使用[name]: value语句。



const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
        const { value, name } = e.target;
        setInput({
            ...input,
            [name]: value
        });
    };


Enter fullscreen mode Exit fullscreen mode

在实现 handleClick 方法之前,我们需要定义一个 props,用于更新和存储系列列表。由于我们已经在App.tsxusing中定义了一个状态useState,因此我们需要将其传递到此Form组件中,并在 handleClick 方法中使用。让我们看看下面的界面。



interface Props {
    seriesList: SeriesProps["seriesList"],
    setSeriesList: Dispatch<SetStateAction<SeriesProps["seriesList"]>>
}


Enter fullscreen mode Exit fullscreen mode

现在我们将实现我们的handleClick方法。



const handleClick = (e: MouseEvent<HTMLButtonElement>) => {
        const { name, genre, cover, imdb, seasons } = input;
        if(!name && !genre && !cover && !imdb && !seasons) return;
        const series = { name, genre, cover, imdb, seasons };
        setSeriesList([...seriesList, series]);
        setInput({
            name: "",
            genre: "",
            cover: "",
            imdb: 0,
            seasons: 0
        });
    };


Enter fullscreen mode Exit fullscreen mode

我们的方法仅接受来自 HTML 按钮元素的鼠标事件。首先,我们解构了输入状态。然后,我们检查是否有任何输入字段为空。如果是,则继续操作。否则,我们创建一个系列对象并将其附加到系列列表中。之后,我们将所有字段清空。因此,我们的完整Form.tsx代码如下所示:



import React, { FC, useState, ChangeEvent, MouseEvent, Dispatch, SetStateAction } from "react";
import { SeriesProps } from "../interfaces/SeriesProps";

interface Props {
    seriesList: SeriesProps["seriesList"],
    setSeriesList: Dispatch<SetStateAction<SeriesProps["seriesList"]>>
}

const Form: FC<Props> = ({ seriesList, setSeriesList }) => {

    const [input, setInput] = useState({
        name: "",
        genre: "",
        cover: "",
        imdb: 0,
        seasons: 0
    });

    const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
        const { value, name } = e.target;
        setInput({
            ...input,
            [name]: value
        });
    };

    const handleClick = (e: MouseEvent<HTMLButtonElement>) => {
        const { name, genre, cover, imdb, seasons } = input;
        const series = { name, genre, cover, imdb, seasons };
        if(!name && !genre && !cover && !imdb && !seasons) return;
        setSeriesList([...seriesList, series]);
        setInput({
            name: "",
            genre: "",
            cover: "",
            imdb: 0,
            seasons: 0
        });
    };

    return (
        <div className="form-container">
            <div className="form-div">
                <label htmlFor="name">Name</label>
                <input type="text" name="name" id="name" value={input.name} onChange={handleChange} />
            </div>
            <div className="form-div">
                <label htmlFor="genre">Genre</label>
                <input type="text" name="genre" id="genre" value={input.genre} onChange={handleChange} />
            </div>
            <div className="form-div">
                <label htmlFor="cover">Cover Link</label>
                <input type="text" name="cover" id="cover" value={input.cover} onChange={handleChange} />
            </div>
            <div className="form-div">
                <label htmlFor="imdb">IMDB Rating</label>
                <input type="number" name="imdb" id="imdb" value={input.imdb} onChange={handleChange} />
            </div>
            <div className="form-div">
                <label htmlFor="seasons">Total Seasons</label>
                <input type="number" name="seasons" id="seasons" value={input.seasons} onChange={handleChange} />
            </div>
            <button type="button" onClick={handleClick}>Add Series</button>
        </div>
    );
};

export default Form;


Enter fullscreen mode Exit fullscreen mode

现在我们只需添加 CSS 样式。为了简单App.css起见,我们只修改了以下文件:



.form-container {
  width: 400px;
  margin: auto;
}

h1 {
  text-align: center;
}

.form-div {
  margin-bottom: 10px;
}

input[type='text'],
input[type='number'] {
  float: right;
  width: 70%;
  padding: 3px;
}

input[type='checkbox'] {
  margin-left: 110px;
}

button {
  margin: 10px 0;
  padding: 10px 0;
  width: 100%;
  cursor: pointer;
  font-weight: bold;
  text-transform: uppercase;
  font-size: 16px;
}

p {
  line-height: 5px;
}

.series-list {
  display: flex;
  flex-flow: wrap;
  margin: 50px auto;
  width: 90%;
}

.series-item {
  padding: 0 20px 20px 0;
  width: 300px;
}


Enter fullscreen mode Exit fullscreen mode

完成所有编码后,我们可以查看浏览器的http://localhost:3000/链接。添加一些数据后,它应该如下所示。整个项目在 GitHub 上。您可以在这里 查看
图片描述

祝您编码愉快😀😀😀😀😀

给我买杯咖啡

文章来源:https://dev.to/alim1496/react-with-typescript-1gp5
PREV
🗿 人类为何发明 HTML - 深入学习前端 - 第一部分
NEXT
Google 软件工程师级别:角色和期望(含薪资)