如何使用 React 和 TypeScript 构建客户列表管理应用程序

作者选择了(https://www.brightfunds.org/funds/tech-education)作为 写给捐款计划的一部分的捐款。

介绍

TypeScript为[JavaScript](https://www.javascript.com/]]开发者如何构建和写出应用程序,特别是网络应用的代码带来了很多改进. 被定义为JavaScript的超集,TypeScript行为与JavaScript相同,但具有额外的功能,旨在帮助开发者用更少或没有bug来构建更大和更复杂的程序. TypeScript越来越受欢迎;被Google等大公司采用为Angular网络框架. [Nest.js] (https://nestjs.com/)后端框架也用TypeScript来建造.

作为开发者提高生产力的方法之一是能够尽快实施新的特性,而不必担心在生产中打破现有的应用。 为了实现这一点,写出静态打字的代码是被许多老练的开发者所采纳的一种风格. 像TypeScript这样的静态打入编程语言对每个有数据类型的变量执行关联;如字符串,整数,布尔等. 使用静态打入编程语言的主要好处之一是类型检查在编译时完成,因此开发者可以在很早的阶段看到其代码出错.

React是一个开源的JavaScript库,开发人员使用它来为可扩展的Web应用程序创建高端用户界面。

在本教程中,您将创建一个客户列表管理应用程序,具有单独的 REST API 后端和与 React 和 TypeScript 构建的前端。您将使用假的 REST API 名为 json-server构建后端。您将使用它快速设置 CRUD (创建,阅读,更新和删除)后端。因此,您可以专注于使用 React 和 TypeScript 来处理应用程序的前端逻辑。

前提条件

要完成本教程,您将需要:

第1步:安装TypeScript并创建React应用程序

在此步骤中,您将使用 Node Package Manager (npm) 在您的计算机上全球安装 TypeScript 包,之后,您还将安装 React 及其依赖,并通过运行开发服务器来检查您的 React 应用程序是否工作。

首先,打开终端并运行以下命令来安装TypeScript:

1npm install -g typescript

安装过程完成后,执行以下命令来检查您的 TypeScript 安装:

1tsc -v

您将看到您计算机上安装的当前版本:

1[secondary_label Output]
2Version 3.4.5

接下来,您将使用 create-react-app 工具来安装 React 应用程序,以便使用一个单一的命令来设置该应用程序。您将使用 npx 命令,这是一个带有 npm 5.2 的包运行工具。 create-react-app 工具具有内置支持,可在不需要任何额外配置的情况下与 TypeScript 工作。 运行以下命令来创建和安装一个名为 `typescript-react-app' 的新的 React 应用程序:

1npx create-react-app typescript-react-app --typescript

之前的命令将创建一个名为typescript-react-app的新 React 应用程序. --typescript 旗帜将 React 组件的默认文件类型设置为.tsx

在本节完成前,应用程序需要从一个端口移动到另一个端口. 为此,您需要为名为 [React Router] (https://www.npmjs.com/package/react-router] 及其相应的TypeScript定义的响应应用程序安装路由库. 您将使用 yarn 为该项目安装库和其他软件包 。 这是因为`yarn'的速度更快,特别是用于安装反应应用程序的依赖性。 移动到新创建的工程文件夹中,然后以以下命令安装React Router:

1cd typescript-react-app
2yarn add react-router-dom

您现在有 React Router 包,该包将为您的项目提供路由功能,然后运行以下命令来安装 React Router 的 TypeScript 定义:

1yarn add @types/react-router-dom

现在,您将安装 axios,这是一个基于浏览器的 HTTP 客户端,以帮助您在应用程序中创建的不同组件执行 HTTP 请求的过程:

1yarn add axios

一旦安装过程完成,请启动开发服务器:

1yarn start

您的应用程序将在http://localhost:3000上运行。

React application homepage

您已经成功安装了 TypeScript,创建了一个新的 React 应用程序,并安装了 React Router,以帮助您从应用程序的一个页面导航到另一个页面。

第2步:创建一个JSON服务器

在此步骤中,您将创建一个模拟服务器,您的React应用程序可以快速连接,以及使用其资源。重要的是要注意,这个后端服务不适合生产中的应用程序。

您可以使用npmyarn在您的计算机上安装json-server。这将使其在您可能需要使用的任何项目目录中可用。打开一个新的终端窗口并运行此命令,在您仍在项目目录中时安装json-server:

1yarn global add json-server

接下来,您将创建一个 JSON 文件,该文件将包含 REST API 将曝光的数据。对于本文件中指定的对象(您将创建的),CRUD 终端将自动生成。

1mkdir server
2cd server

现在,使用nano创建并打开名为db.json的新文件:

1nano db.json

将以下内容添加到文件中:

 1[label /server/db.json]
 2{
 3    "customers": [
 4        {
 5            "id": 1,
 6            "first_name": "Customer_1",
 7            "last_name": "Customer_11",
 8            "email": "[email protected]",
 9            "phone": "00000000000",
10            "address": "Customer_1 Address",
11            "description": "Customer_1 description"
12        },
13        {
14            "id": 2,
15            "first_name": "Customer_2",
16            "last_name": "Customer_2",
17            "email": "[email protected]",
18            "phone": "00000000000",
19            "address": "Customer_2 Adress",
20            "description": "Customer_2 Description"
21        }
22    ]
23}

JSON 结构由一个客户端对象组成,每个客户端由七个属性组成:id、description、first_name、last_name、email、电话和地址。

保存和退出文件。

默认情况下,json-server运行在端口3000上,这是你的React应用程序运行的相同端口. 为了避免冲突,你可以更改json-server的默认端口。

1cd ~/typescript-react-app

使用您喜爱的文本编辑器打开应用程序,并创建一个名为 `json-server.json'的新文件:

1nano json-server.json

现在输入以下内容来更新端口号码:

1[label /json-server.json]
2{
3    "port": 5000
4}

这将作为json-server的配置文件,并确保服务器始终运行在其指定的端口上。

保存和退出文件。

要运行服务器,请使用以下命令:

1json-server --watch server/db.json

如果您在浏览器中导航到http://localhost:5000/customers,您将看到服务器显示您的客户列表。

Customer list shown by json-server

为了简化运行json-server的过程,您可以用名为server的新属性更新package.jsonscripts对象,如下所示:

 1[label /package.json]
 2{
 3...
 4  "scripts": {
 5    "start": "react-scripts start",
 6    "build": "react-scripts build",
 7    "test": "react-scripts test",
 8    "eject": "react-scripts eject",
 9    "server": "json-server --watch server/db.json"
10  },
11...
12}

保存和退出文件。

现在,任何时候你想要启动json服务器,你只需要从终端运行yarn服务器

您创建了一个简单的 REST API,将其用作此应用程序的后端服务器。您还创建了一个客户端 JSON 对象,将其用作 REST API 的默认数据。

第3步:创建可重复使用的组件

在本节中,您将为应用程序创建所需的 React 组件. 这将包括用于创建,显示和编辑数据库中特定客户的详细信息的组件。

首先,回到您运行 React 应用程序的终端,然后用 CTRL + C 停止开发服务器。

1cd ./src/

然后,在里面创建一个名为组件的新文件夹,然后移动到新的文件夹:

1mkdir components
2cd components

在新创建的文件夹中,创建一个客户文件夹,然后进入它:

1mkdir customer
2cd customer

现在创建两个名为Create.tsxEdit.tsx的新文件:

1touch Create.tsx Edit.tsx

这些文件是 React 可重复使用的组件,这些组件将渲染表单,并具有创建和编辑客户详细信息的所有业务逻辑。

在文本编辑器中打开Create.tsx文件,然后添加以下代码:

 1[label /src/components/customer/Create.tsx]
 2import * as React from 'react';
 3import axios from 'axios';
 4import { RouteComponentProps, withRouter } from 'react-router-dom';
 5
 6export interface IValues {
 7    first_name: string,
 8    last_name: string,
 9    email: string,
10    phone: string,
11    address: string,
12    description: string,
13}
14export interface IFormState {
15    [key: string]: any;
16    values: IValues[];
17    submitSuccess: boolean;
18    loading: boolean;
19}

在这里,您已经导入了从 React Router 包中导航所需的 Reactaxios 和其他必要组件,然后您创建了两个名为 IValues 和 `IFormState' 的新接口。 TypeScript interfaces有助于定义应该传递给对象的特定类型的值,并在整个应用程序中执行一致性。

接下来,您将构建一个扩展React.ComponentCreate组件,在IFormState接口后立即将下列代码添加到Create.tsx文件中:

 1[label /src/components/customer/Create.tsx]
 2...
 3class Create extends React.Component<RouteComponentProps, IFormState> {
 4    constructor(props: RouteComponentProps) {
 5        super(props);
 6        this.state = {
 7            first_name: '',
 8            last_name: '',
 9            email: '',
10            phone: '',
11            address: '',
12            description: '',
13            values: [],
14            loading: false,
15            submitSuccess: false,
16        }
17    }
18}
19export default withRouter(Create)

在这里,您在 Typescript 中定义了 React 组件. 在这种情况下,‘Create’ 类组件接受‘props’(简称)的类型‘RouteComponentProps’,并使用一个类型的状态‘IFormState’。

接下来,在创建类组件中添加这些方法,就在构建程序之后,您将使用这些方法来处理客户表单并处理输入字段中的所有更改:

 1[label /src/components/customer/Create.tsx]
 2...
 3          values: [],
 4          loading: false,
 5          submitSuccess: false,
 6      }
 7  }
 8
 9  private processFormSubmission = (e: React.FormEvent<HTMLFormElement>): void => {
10          e.preventDefault();
11          this.setState({ loading: true });
12          const formData = {
13              first_name: this.state.first_name,
14              last_name: this.state.last_name,
15              email: this.state.email,
16              phone: this.state.phone,
17              address: this.state.address,
18              description: this.state.description,
19          }
20          this.setState({ submitSuccess: true, values: [...this.state.values, formData], loading: false });
21          axios.post(`http://localhost:5000/customers`, formData).then(data => [
22              setTimeout(() => {
23                  this.props.history.push('/');
24              }, 1500)
25          ]);
26      }
27
28      private handleInputChanges = (e: React.FormEvent<HTMLInputElement>) => {
29          e.preventDefault();
30          this.setState({
31              [e.currentTarget.name]: e.currentTarget.value,
32      })
33  }
34
35...
36export default withRouter(Create)
37...

processFormSubmission()方法从应用程序状态中接收客户的详细信息,并使用axios将其发送到数据库中。

接下来,在)方法立即在handleInputchanges()`方法后添加。

 1[label /src/components/customer/Create.tsx]
 2...
 3  public render() {
 4      const { submitSuccess, loading } = this.state;
 5      return (
 6          <div>
 7              <div className={"col-md-12 form-wrapper"}>
 8                  <h2> Create Post </h2>
 9                  {!submitSuccess && (
10                      <div className="alert alert-info" role="alert">
11                          Fill the form below to create a new post
12                  </div>
13                  )}
14                  {submitSuccess && (
15                      <div className="alert alert-info" role="alert">
16                          The form was successfully submitted!
17                          </div>
18                  )}
19                  <form id={"create-post-form"} onSubmit={this.processFormSubmission} noValidate={true}>
20                      <div className="form-group col-md-12">
21                          <label htmlFor="first_name"> First Name </label>
22                          <input type="text" id="first_name" onChange={(e) => this.handleInputChanges(e)} name="first_name" className="form-control" placeholder="Enter customer's first name" />
23                      </div>
24                      <div className="form-group col-md-12">
25                          <label htmlFor="last_name"> Last Name </label>
26                          <input type="text" id="last_name" onChange={(e) => this.handleInputChanges(e)} name="last_name" className="form-control" placeholder="Enter customer's last name" />
27                      </div>
28                      <div className="form-group col-md-12">
29                          <label htmlFor="email"> Email </label>
30                          <input type="email" id="email" onChange={(e) => this.handleInputChanges(e)} name="email" className="form-control" placeholder="Enter customer's email address" />
31                      </div>
32                      <div className="form-group col-md-12">
33                          <label htmlFor="phone"> Phone </label>
34                          <input type="text" id="phone" onChange={(e) => this.handleInputChanges(e)} name="phone" className="form-control" placeholder="Enter customer's phone number" />
35                      </div>
36                      <div className="form-group col-md-12">
37                          <label htmlFor="address"> Address </label>
38                          <input type="text" id="address" onChange={(e) => this.handleInputChanges(e)} name="address" className="form-control" placeholder="Enter customer's address" />
39                      </div>
40                      <div className="form-group col-md-12">
41                          <label htmlFor="description"> Description </label>
42                          <input type="text" id="description" onChange={(e) => this.handleInputChanges(e)} name="description" className="form-control" placeholder="Enter Description" />
43                      </div>
44                      <div className="form-group col-md-4 pull-right">
45                          <button className="btn btn-success" type="submit">
46                              Create Customer
47                          </button>
48                          {loading &&
49                              <span className="fa fa-circle-o-notch fa-spin" />
50                          }
51                      </div>
52                  </form>
53              </div>
54          </div>
55      )
56  }
57...

在此,您创建了含有输入字段的表格,以持有客户的 " 第一 " 、 " 最后 " 、 " 电子邮件 " 、 " 电话 " 、 " 地址 " 和 " 描述 " 等值。 每个输入字段都有手动输入变化方法。 以输入字段获得的值更新状态。 此外,根据应用程序的状态,一个名为提交Success的布尔变量将控制应用程序在创建新客户之前和之后显示的信息.

你可以看到这个文件的完整代码在这个GitHub存储库(https://github.com/yemiwebby/typescript-react-customer-app/blob/master/src/components/customer/Create.tsx)。

保存并退出Create.tsx

现在,您已将适当的逻辑添加到应用程序的创建组件文件中,您将继续为编辑组件文件添加内容。

客户文件夹中打开Edit.tsx文件,并开始添加以下内容来导入React,axios,并定义TypeScript界面:

 1[label /src/components/customer/Edit.tsx]
 2import * as React from 'react';
 3import { RouteComponentProps, withRouter } from 'react-router-dom';
 4import axios from 'axios';
 5
 6export interface IValues {
 7    [key: string]: any;
 8}
 9export interface IFormState {
10    id: number,
11    customer: any;
12    values: IValues[];
13    submitSuccess: boolean;
14    loading: boolean;
15}

创建组件类似,您将导入所需的模块,并分别创建IValuesIFormState接口。

接下来,如下所示,直接在IFormState界面块后创建EditCustomer类组件:

 1[label /src/components/customer/Edit.tsx]
 2...
 3class EditCustomer extends React.Component<RouteComponentProps<any>, IFormState> {
 4    constructor(props: RouteComponentProps) {
 5        super(props);
 6        this.state = {
 7            id: this.props.match.params.id,
 8            customer: {},
 9            values: [],
10            loading: false,
11            submitSuccess: false,
12        }
13    }
14}
15export default withRouter(EditCustomer)

此组件将RouteComponentProps<any>IFormState的界面作为参数。 您将RouteComponentProps添加到<any>,因为每当 React Router 分析路径参数时,它不会进行任何类型的转换来确定数据类型是否为数字字符串

现在在组件中添加以下方法:

 1[label /src/components/customer/Edit.tsx]
 2...
 3    public componentDidMount(): void {
 4        axios.get(`http://localhost:5000/customers/${this.state.id}`).then(data => {
 5            this.setState({ customer: data.data });
 6        })
 7    }
 8
 9    private processFormSubmission = async (e: React.FormEvent<HTMLFormElement>): Promise<void> => {
10        e.preventDefault();
11        this.setState({ loading: true });
12        axios.patch(`http://localhost:5000/customers/${this.state.id}`, this.state.values).then(data => {
13            this.setState({ submitSuccess: true, loading: false })
14            setTimeout(() => {
15                this.props.history.push('/');
16            }, 1500)
17        })
18    }
19
20    private setValues = (values: IValues) => {
21        this.setState({ values: { ...this.state.values, ...values } });
22    }
23    private handleInputChanges = (e: React.FormEvent<HTMLInputElement>) => {
24        e.preventDefault();
25        this.setValues({ [e.currentTarget.id]: e.currentTarget.value })
26    }
27...
28}
29
30export default withRouter(EditCustomer)

首先,您添加了一种componentDidMount()方法,该方法是在创建组件时被调用的一种生命周期方法。该方法使用从路径参数中获得的id来识别特定客户作为参数,使用它来从数据库中获取他们的详细信息,然后将该表单填充到其中。

最后,为)`方法:

 1[label /src/components/customer/Edit.tsx]
 2...
 3    public render() {
 4        const { submitSuccess, loading } = this.state;
 5        return (
 6            <div className="App">
 7                {this.state.customer &&
 8                    <div>
 9                        < h1 > Customer List Management App</h1>
10                        <p> Built with React.js and TypeScript </p>
11
12                        <div>
13                            <div className={"col-md-12 form-wrapper"}>
14                                <h2> Edit Customer </h2>
15                                {submitSuccess && (
16                                    <div className="alert alert-info" role="alert">
17                                        Customer's details has been edited successfully </div>
18                                )}
19                                <form id={"create-post-form"} onSubmit={this.processFormSubmission} noValidate={true}>
20                                    <div className="form-group col-md-12">
21                                        <label htmlFor="first_name"> First Name </label>
22                                        <input type="text" id="first_name" defaultValue={this.state.customer.first_name} onChange={(e) => this.handleInputChanges(e)} name="first_name" className="form-control" placeholder="Enter customer's first name" />
23                                    </div>
24                                    <div className="form-group col-md-12">
25                                        <label htmlFor="last_name"> Last Name </label>
26                                        <input type="text" id="last_name" defaultValue={this.state.customer.last_name} onChange={(e) => this.handleInputChanges(e)} name="last_name" className="form-control" placeholder="Enter customer's last name" />
27                                    </div>
28                                    <div className="form-group col-md-12">
29                                        <label htmlFor="email"> Email </label>
30                                        <input type="email" id="email" defaultValue={this.state.customer.email} onChange={(e) => this.handleInputChanges(e)} name="email" className="form-control" placeholder="Enter customer's email address" />
31                                    </div>
32                                    <div className="form-group col-md-12">
33                                        <label htmlFor="phone"> Phone </label>
34                                        <input type="text" id="phone" defaultValue={this.state.customer.phone} onChange={(e) => this.handleInputChanges(e)} name="phone" className="form-control" placeholder="Enter customer's phone number" />
35                                    </div>
36                                    <div className="form-group col-md-12">
37                                        <label htmlFor="address"> Address </label>
38                                        <input type="text" id="address" defaultValue={this.state.customer.address} onChange={(e) => this.handleInputChanges(e)} name="address" className="form-control" placeholder="Enter customer's address" />
39                                    </div>
40                                    <div className="form-group col-md-12">
41                                        <label htmlFor="description"> Description </label>
42                                        <input type="text" id="description" defaultValue={this.state.customer.description} onChange={(e) => this.handleInputChanges(e)} name="description" className="form-control" placeholder="Enter Description" />
43                                    </div>
44                                    <div className="form-group col-md-4 pull-right">
45                                        <button className="btn btn-success" type="submit">
46                                            Edit Customer </button>
47                                        {loading &&
48                                            <span className="fa fa-circle-o-notch fa-spin" />
49                                        }
50                                    </div>
51                                </form>
52                            </div>
53                        </div>
54                    </div>
55                }
56            </div>
57        )
58    }
59...

在这里,您创建了一个表单来编辑特定客户的详细信息,然后将该表单中的输入字段填充到您的应用程序状态获得的客户的详细信息中。

你可以看到这个文件的完整代码在这个GitHub存储库(https://github.com/yemiwebby/typescript-react-customer-app/blob/master/src/components/customer/Edit.tsx)。

保存并退出Edit.tsx

要查看应用程序内创建的客户的完整列表,您将在 ./src/components 文件夹中创建一个新组件,并将其命名为 Home.tsx:

1cd ./src/components
2nano Home.tsx

添加以下内容:

 1[label /src/components/Home.tsx]
 2import * as React from 'react';
 3import { Link, RouteComponentProps } from 'react-router-dom';
 4import axios from 'axios';
 5
 6interface IState {
 7    customers: any[];
 8}
 9
10export default class Home extends React.Component<RouteComponentProps, IState> {
11    constructor(props: RouteComponentProps) {
12        super(props);
13        this.state = { customers: [] }
14    }
15    public componentDidMount(): void {
16        axios.get(`http://localhost:5000/customers`).then(data => {
17            this.setState({ customers: data.data })
18        })
19    }
20    public deleteCustomer(id: number) {
21        axios.delete(`http://localhost:5000/customers/${id}`).then(data => {
22            const index = this.state.customers.findIndex(customer => customer.id === id);
23            this.state.customers.splice(index, 1);
24            this.props.history.push('/');
25        })
26    }
27}

在这里,您已经从 React Router 中导入了React,axios和其他必要组件,您在Home组件中创建了两种新方法:

  • componentDidMount(): 应用程序在组件安装后立即调用此方法. 其职责在这里是检索客户列表并与之更新主页. * deleteCustomer(): 此方法将接受一个 id 作为参数,并将从数据库中删除与此 id 识别的客户的详细信息。

现在添加render()方法来显示包含Home组件的客户列表的表格:

 1[label /src/components/Home.tsx]
 2...
 3public render() {
 4        const customers = this.state.customers;
 5        return (
 6            <div>
 7                {customers.length === 0 && (
 8                    <div className="text-center">
 9                        <h2>No customer found at the moment</h2>
10                    </div>
11                )}
12                <div className="container">
13                    <div className="row">
14                        <table className="table table-bordered">
15                            <thead className="thead-light">
16                                <tr>
17                                    <th scope="col">Firstname</th>
18                                    <th scope="col">Lastname</th>
19                                    <th scope="col">Email</th>
20                                    <th scope="col">Phone</th>
21                                    <th scope="col">Address</th>
22                                    <th scope="col">Description</th>
23                                    <th scope="col">Actions</th>
24                                </tr>
25                            </thead>
26                            <tbody>
27                                {customers && customers.map(customer =>
28                                    <tr key={customer.id}>
29                                        <td>{customer.first_name}</td>
30                                        <td>{customer.last_name}</td>
31                                        <td>{customer.email}</td>
32                                        <td>{customer.phone}</td>
33                                        <td>{customer.address}</td>
34                                        <td>{customer.description}</td>
35                                        <td>
36                                            <div className="d-flex justify-content-between align-items-center">
37                                                <div className="btn-group" style={{ marginBottom: "20px" }}>
38                                                    <Link to={`edit/${customer.id}`} className="btn btn-sm btn-outline-secondary">Edit Customer </Link>
39                                                    <button className="btn btn-sm btn-outline-secondary" onClick={() => this.deleteCustomer(customer.id)}>Delete Customer</button>
40                                                </div>
41                                            </div>
42                                        </td>
43                                    </tr>
44                                )}
45                            </tbody>
46                        </table>
47                    </div>
48                </div>
49            </div>
50        )
51    }
52...

在此代码块中,您从应用程序的状态中获取客户列表作为一个数组,重复它,并在HTML表中显示它,您还添加了customer.id参数,该方法用于识别和删除特定客户的详细信息。

保存并退出Home.tsx

您已通过使用界面来定义组件和附件的类型来对本应用程序创建的所有组件采用静态打字原则,这是使用React应用程序使用TypeScript的最佳方法之一。

此时,您已经完成了为应用程序创建所需的所有可重复使用的组件,您现在可以更新应用程序组件,并链接到您迄今为止创建的所有组件。

步骤4 – 设置路由和更新应用程序的入口点

在此步骤中,您将从 React Router 包中导入必要的组件,并配置应用组件,以便根据加载的路径返回不同的组件. 这将允许您导航应用程序的不同页面。

请导航到 ./src/App.tsx:

1nano App.tsx

然后将其内容替换为如下:

 1[label /src/App.tsx]
 2import * as React from 'react';
 3import './App.css';
 4import { Switch, Route, withRouter, RouteComponentProps, Link } from 'react-router-dom';
 5import Home from './components/Home';
 6import Create from './components/customer/Create';
 7import EditCustomer from './components/customer/Edit';
 8
 9class App extends React.Component<RouteComponentProps<any>> {
10  public render() {
11    return (
12      <div>
13        <nav>
14          <ul>
15            <li>
16              <Link to={'/'}> Home </Link>
17            </li>
18            <li>
19              <Link to={'/create'}> Create Customer </Link>
20            </li>
21          </ul>
22        </nav>
23        <Switch>
24          <Route path={'/'} exact component={Home} />
25          <Route path={'/create'} exact component={Create} />
26          <Route path={'/edit/:id'} exact component={EditCustomer} />
27        </Switch>
28      </div>
29    );
30  }
31}
32export default withRouter(App);

您从 React Router 包中导入了所有必要的组件,并导入了可重复使用的组件,用于创建、编辑和查看客户详细信息。

保存并退出App.tsx

......................................................................................................................................................................................................

 1[label /src/index.tsx]
 2import React from 'react';
 3import ReactDOM from 'react-dom';
 4import './index.css';
 5import App from './App';
 6import { BrowserRouter } from 'react-router-dom'; 
 7import * as serviceWorker from './serviceWorker';
 8ReactDOM.render(
 9    <BrowserRouter>
10        <App />
11    </BrowserRouter>
12    , document.getElementById('root')
13);
14serviceWorker.unregister();

React Router 使用BrowserRouter组件来让您的应用程序了解导航,例如历史和当前路径。

一旦你完成了编辑Index.tsx,保存和退出。

最后,你会使用Bootstrap来添加一些风格到你的应用程序。Bootstrap(https://getbootstrap.com/)是一个流行的HTML,CSS和JavaScript框架,用于在Web上开发响应性,移动第一的项目。它允许开发人员构建一个有吸引力的用户界面,而无需写太多CSS。它配备了一个响应的网格系统,为网页提供了一个完成的外观,在所有设备上工作。

要为您的应用程序添加 Bootstrap 和样式,请将 `./src/App.css’ 的内容替换为以下内容:

 1[label /src/App.css]
 2@import 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css';
 3
 4.form-wrapper {
 5  width: 500px;
 6  margin: 0 auto;
 7}
 8.App {
 9  text-align: center;
10  margin-top: 30px;
11}
12nav {
13  width: 300px;
14  margin: 0 auto;
15  background: #282c34;
16  height: 70px;
17  line-height: 70px;
18}
19nav ul li {
20  display: inline;
21  list-style-type: none;
22  text-align: center;
23  padding: 30px;
24}
25nav ul li a {
26  margin: 50px 0;
27  font-weight: bold;
28  color: white;
29  text-decoration: none;
30}
31nav ul li a:hover {
32  color: white;
33  text-decoration: none;
34}
35table {
36  margin-top: 50px;
37}
38.App-link {
39  color: #61dafb;
40}
41@keyframes App-logo-spin {
42  from {
43    transform: rotate(0deg);
44  }
45  to {
46    transform: rotate(360deg);
47  }
48}

你在这里使用 Bootstrap 来增强应用程序的外观和感觉,通过给它默认布局,风格和颜色,你还添加了一些自定义风格,特别是导航栏。

保存并退出App.css

在本节中,您已配置 React Router 以根据用户访问的路线来渲染合适的组件,并添加了一些风格来使应用程序对用户更具吸引力。

步骤5:运行您的应用程序

现在,您已经通过创建多个可重复使用的组件来设置了该应用程序的前端,并使用json-server构建了REST API,您可以运行您的应用程序。

返回项目的 root 文件夹:

1cd ~/typescript-react-app

接下来运行以下命令来启动您的应用程序:

1yarn start

<$>[注] 注: 请确保您的服务器仍然在其他终端窗口中运行。

点击http://localhost:3000查看您的浏览器中的应用程序,然后继续点击创建按钮,填写客户的详细信息。

Create customer page

在输入字段中输入相应的值后,点击创建客户按钮来提交表单。

View customers page

点击任何行中的 编辑客户端 按钮,您将被引导到该行上的相应客户端的编辑功能的页面。

Edit customer page

编辑客户的详细信息,然后单击编辑客户更新客户的详细信息。

您已运行您的应用程序,以确保所有组件正常工作. 使用您的应用程序的不同页面,您已创建并编辑了客户条目。

结论

在本教程中,您使用 ReactTypeScript构建了客户列表管理应用程序。本教程中的过程是使用 JavaScript 作为与 React 构建应用程序的常规方式的偏差。

要继续开发这个项目,你可以将你的模仿后端服务器移动到一个生产准备的后端技术,如 ExpressNest.js

您可以在GitHub上找到该项目的完整源代码(https://github.com/yemiwebby/typescript-react-customer-app)。

Published At
Categories with 技术
comments powered by Disqus