ReactとTypeScriptを使用して顧客リスト管理アプリを構築する方法

_著者は、https://www.brightfunds.org/funds/tech-education [Tech Education Fund]を選択して、https://do.co/w4do-cta [Write for DOnations]プログラムの一環として寄付を受け取りました。 _

前書き

TypeScriptは、https://www.javascript.com/ [JavaScript]開発者がアプリ(特にWebアプリケーション)のコードを構造化して記述する方法を大幅に改善しました。 JavaScriptのスーパーセットとして定義されているTypeScriptは、JavaScriptと同じように動作しますが、開発者がバグの少ないまたはまったくないより大きく複雑なプログラムを構築できるように設計された追加機能を備えています。 TypeScriptの人気はますます高まっています。 Angular WebフレームワークのためにGoogleのような主要企業に採用されました。 Nest.jsバックエンドフレームワークもTypeScriptで構築されました。

開発者として生産性を向上させる方法の1つは、実稼働中の既存のアプリを壊す心配をせずに、できるだけ早く新機能を実装できることです。 これを実現するために、静的に型指定されたコードを記述することは、多くのベテラン開発者が採用しているスタイルです。 TypeScriptのような静的に型付けされたプログラミング言語は、すべての変数とデータ型の関連付けを強制します。文字列、整数、ブール値など。 静的に型付けされたプログラミング言語を使用する主な利点の1つは、型チェックがコンパイル時に完了するため、開発者が非常に早い段階でコードのエラーを確認できることです。

ReactはオープンソースのJavaScriptライブラリで、開発者はこれを使用してスケーラブルなWebアプリケーション用のハイエンドユーザーインターフェイスを作成します。 単一ページアプリケーション向けにReactで構築された優れたパフォーマンスと動的なユーザーインターフェイスにより、開発者の間で人気があります。

このチュートリアルでは、別個のREST APIバックエンドと、ReactおよびTypeScriptで構築されたフロントエンドを備えた顧客リスト管理アプリケーションを作成します。 https://github.com/typicode/json-server [+ json-server +]という名前の偽のR​​EST APIを使用してバックエンドを構築します。 これを使用して、CRUD(作成、読み取り、更新、削除)バックエンドをすばやくセットアップします。 したがって、ReactとTypeScriptを使用して、アプリケーションのフロントエンドロジックの処理に集中できます。

前提条件

このチュートリアルを完了するには、次のものが必要です。

  • Node.js(少なくともv6)およびhttps://www.npmjs.com/ [+ npm +](少なくともv5.2)のローカルインストール。 Node.jsは、ブラウザーの外部でコードを実行できるJavaScriptランタイム環境です。 `+ npm +`というプリインストールされたパッケージマネージャーが付属しており、パッケージのインストールと更新ができます。 これらをmacOSまたはUbuntu 18.04にインストールするには、https://www.digitalocean.com/community/tutorials/how-to-install-node-js-and-create-a-local-development-environment-onの手順に従います-macos [macOSでNode.jsをインストールしてローカル開発環境を作成する方法]またはhttps://www.digitalocean.com/community/tutorials/how-to-install-node-の「PPAを使用してインストールする」セクションjs-on-ubuntu-18-04 [Ubuntu 18.04にNode.jsをインストールする方法]。

  • Yarnのローカルインストール。 https://yarnpkg.com/en/docs/install#mac-stable [これらの手順に従う]を使用して、オペレーティングシステムにYarnをインストールします。

  • TypeScriptとhttps://www.digitalocean.com/community/tutorial_series/how-to-code-in-javascript[JavaScript]の基本的な理解。

  • テキストエディターがインストールされている。 Visual Studio Code、https://atom.io/ [Atom]、またはhttps://www.sublimetext.com/[Sublime Text]など。

ステップ1-TypeScriptのインストールとReactアプリケーションの作成

このステップでは、Node Package Manager( + npm +)を使用して、TypeScriptパッケージをマシンにグローバルにインストールします。 その後、Reactとその依存関係もインストールし、開発サーバーを実行してReactアプリが動作していることを確認します。

開始するには、ターミナルを開き、次のコマンドを実行してTypeScriptをインストールします。

npm install -g typescript

インストールプロセスが完了したら、次のコマンドを実行して、TypeScriptのインストールを確認します。

tsc -v

マシンにインストールされている現在のバージョンが表示されます。

OutputVersion

次に、https://github.com/facebook/create-react-app [+ create-react-app +]ツールを使用して1つのコマンドでアプリケーションをセットアップすることにより、Reactアプリケーションをインストールします。 + npm + 5.2+に付属するパッケージランナーツールである `+ npx `コマンドを使用します。 ` create-react-app `ツールには、追加の設定を必要とせずにTypeScriptを操作するためのサポートが組み込まれています。 次のコマンドを実行して、 `+`という名前の新しいReactアプリケーションを作成してインストールします。

npx create-react-app  --typescript

上記のコマンドは、 `+`という名前の新しいReactアプリケーションを作成します。 `-typescript `フラグは、Reactコンポーネントのデフォルトのファイルタイプを ` .tsx +`に設定します。

このセクションを完了する前に、アプリケーションはポート間を移動する必要があります。 それには、https://www.npmjs.com/package/react-router [React Router]という名前のReactアプリケーションのルーティングライブラリと、それに対応するTypeScript定義をインストールする必要があります。 このプロジェクトのライブラリと他のパッケージをインストールするには、 `+ yarn `を使用します。 これは、特にReactアプリケーションの依存関係をインストールする場合、 ` yarn +`の方が高速だからです。 新しく作成したプロジェクトフォルダーに移動し、次のコマンドでReact Routerをインストールします。

cd
yarn add react-router-dom

これで、プロジェクト内でルーティング機能を提供するReact Routerパッケージができました。 次に、次のコマンドを実行して、React RouterのTypeScript定義をインストールします。

yarn add @types/react-router-dom

次に、https://github.com/axios/axios [+ axios +]をインストールします。これは、約束されたブラウザー用のHTTPクライアントであり、さまざまなコンポーネントからHTTPリクエストを実行するプロセスを支援します。アプリケーション内で作成:

yarn add axios

インストールプロセスが完了したら、次を使用して開発サーバーを起動します。

yarn start

アプリケーションは `+ http:// localhost:3000 +`で実行されます。

image:https://assets.digitalocean.com/articles/reacttypescript/step1.png [Reactアプリケーションのホームページ]

アプリケーションのあるページから別のページへの移動を支援するために、TypeScriptのインストール、新しいReactアプリケーションの作成、React Routerのインストールが正常に完了しました。 次のセクションでは、アプリケーションのバックエンドサーバーを設定します。

ステップ2-JSONサーバーの作成

このステップでは、Reactアプリケーションがすばやく接続できる模擬サーバーを作成し、そのリソースを使用します。 このバックエンドサービスは、運用環境のアプリケーションには適していないことに注意することが重要です。 Nest.js、Express、またはその他のバックエンドテクノロジーを使用して、実稼働環境でRESTful APIを構築できます。 `+ json-server +`は、プロトタイプを作成してバックエンドサーバーをモックする必要がある場合に便利なツールです。

+ npm`または + yarn`を使用して、マシンに `+ json-server`をインストールできます。 これにより、プロジェクトを使用する必要がある場合に、プロジェクトの任意のディレクトリから使用できるようになります。 プロジェクトディレクトリ内にいる間に、新しいターミナルウィンドウを開き、このコマンドを実行して `+ json-server +`をインストールします。

yarn global add json-server

次に、REST APIによって公開されるデータを含むJSONファイルを作成します。 このファイル(作成するファイル)で指定されたオブジェクトに対して、CRUDエンドポイントが自動的に生成されます。 最初に、 `+ server +`という名前の新しいフォルダーを作成し、そこに移動します:

mkdir server
cd server

次に、 `+ nano `を使用して、 ` db.json +`という名前の新しいファイルを作成して開きます。

nano db.json

次のコンテンツをファイルに追加します。

/server/db.json

{
   "customers": [
       {
           "id": 1,
           "first_name": "Customer_1",
           "last_name": "Customer_11",
           "email": "[email protected]",
           "phone": "00000000000",
           "address": "Customer_1 Address",
           "description": "Customer_1 description"
       },
       {
           "id": 2,
           "first_name": "Customer_2",
           "last_name": "Customer_2",
           "email": "[email protected]",
           "phone": "00000000000",
           "address": "Customer_2 Adress",
           "description": "Customer_2 Description"
       }
   ]
}

JSON構造は、2つのデータセットが割り当てられた顧客オブジェクトで構成されます。 各顧客は、「+ id 」、「 description」、「+ first_name」、「+ last_name」、「+ email 」、「 phone 」、および「 address +」の7つのプロパティで構成されています。

ファイルを保存して終了します。

デフォルトでは、 `+ json-server `はポート ` 3000 `で実行されます。これは、Reactアプリケーションが実行されるポートと同じです。 競合を避けるために、 ` json-server`のデフォルトのポートを変更できます。 これを行うには、アプリケーションのルートディレクトリに移動します。

cd ~/

任意のテキストエディターでアプリケーションを開き、 `+ json-server.json +`という名前の新しいファイルを作成します。

nano json-server.json

次に、次を挿入してポート番号を更新します。

/json-server.json

{
   "port": 5000
}

これは、 `+ json-server +`の設定ファイルとして機能し、サーバーが常に指定されたポートで実行されるようにします。

ファイルを保存して終了します。

サーバーを実行するには、次のコマンドを使用します。

json-server --watch server/db.json

これにより、ポート「5000」で「+ json-server」が起動します。 ブラウザで `+ http:// localhost:5000 / customers +`に移動すると、サーバーに顧客リストが表示されます。

image:https://assets.digitalocean.com/articles/reacttypescript/step2.png [json-serverが表示する顧客リスト]

+ json-server +`の実行プロセスを効率化するために、次のように `+ package.json`を + server + という名前の新しいプロパティで + scripts + `オブジェクトに更新できます。

/package.json

{
...
 "scripts": {
   "start": "react-scripts start",
   "build": "react-scripts build",
   "test": "react-scripts test",
   "eject": "react-scripts eject",

 },
...
}

ファイルを保存して終了します。

これで、 `+ json-server `を起動したいときはいつでも、ターミナルから ` yarn server +`を実行するだけです。

このアプリケーションのバックエンドサーバーとして使用する簡単なREST APIを作成しました。 また、REST APIのデフォルトデータとして使用される顧客JSONオブジェクトも作成しました。 最後に、 `+ json-server +`を搭載したバックエンドサーバーの代替ポートを設定しました。 次に、アプリケーションの再利用可能なコンポーネントを構築します。

手順3-再利用可能なコンポーネントの作成

このセクションでは、アプリケーションに必要なReactコンポーネントを作成します。 これには、データベース内の特定の顧客の詳細をそれぞれ作成、表示、編集するコンポーネントが含まれます。 また、アプリケーションのTypeScriptインターフェイスの一部を構築します。

開始するには、Reactアプリケーションを実行しているターミナルに戻り、 `+ CTRL + C `で開発サーバーを停止します。 次に、 `。/ src / +`フォルダーに移動します。

cd ./src/

次に、その中に「+ components」という名前の新しいフォルダーを作成し、新しいフォルダーに移動します。

mkdir components
cd components

新しく作成したフォルダー内で、 `+ customer +`フォルダーを作成し、そこに移動します。

mkdir customer
cd customer

次に、 `+ Create.tsx `と ` Edit.tsx +`という名前の2つの新しいファイルを作成します。

touch Create.tsx Edit.tsx

これらのファイルは、フォームをレンダリングし、それぞれ顧客の詳細を作成および編集するためのすべてのビジネスロジックを保持するReactの再利用可能なコンポーネントです。

テキストエディタで `+ Create.tsx +`ファイルを開き、次のコードを追加します。

/src/components/customer/Create.tsx

import * as React from 'react';
import axios from 'axios';
import { RouteComponentProps, withRouter } from 'react-router-dom';

export interface IValues {
   first_name: string,
   last_name: string,
   email: string,
   phone: string,
   address: string,
   description: string,
}
export interface IFormState {
   [key: string]: any;
   values: IValues[];
   submitSuccess: boolean;
   loading: boolean;
}

ここで、 + React ++ axios +、およびReact Routerパッケージからのルーティングに必要なその他の必要なコンポーネントをインポートしました。 その後、 `+ IValues `と ` IFormState +`という名前の2つの新しいインターフェイスを作成しました。 TypeScript interfacesは、オブジェクトに渡される特定のタイプの値を定義し、アプリケーション全体で一貫性を保つのに役立ちます。 これにより、プログラムにバグが発生する可能性が低くなります。

次に、 + React.Component`を拡張する + Create`コンポーネントを構築します。 次のコードを `+ IFormState `インターフェースの直後の ` Create.tsx +`ファイルに追加します。

/src/components/customer/Create.tsx

...
class Create extends React.Component<RouteComponentProps, IFormState> {
   constructor(props: RouteComponentProps) {
       super(props);
       this.state = {
           first_name: '',
           last_name: '',
           email: '',
           phone: '',
           address: '',
           description: '',
           values: [],
           loading: false,
           submitSuccess: false,
       }
   }
}
export default withRouter(Create)

ここで、TypescriptでReactコンポーネントを定義しました。 この場合、 + Create +`クラスコンポーネントは、タイプ `+ RouteComponentProps +`の `+ props +(「プロパティ」の略)を受け入れ、タイプ `+ IFormState `の状態を使用します。 次に、コンストラクター内で、 ` state +`オブジェクトを初期化し、顧客のレンダリングされた値を表すすべての変数を定義しました。

次に、コンストラクタの直後に、これらのメソッドを `+ Create +`クラスコンポーネント内に追加します。 これらのメソッドを使用して、顧客フォームを処理し、入力フィールドのすべての変更を処理します。

/src/components/customer/Create.tsx

...
         values: [],
         loading: false,
         submitSuccess: false,
     }
 }



























...
export default withRouter(Create)
...

`+ processFormSubmission()`メソッドは、アプリケーションの状態から顧客の詳細を受け取り、 ` axios `を使用してデータベースに投稿します。 ` handleInputChanges()`は、 ` React.FormEvent `を使用してすべての入力フィールドの値を取得し、 ` this.setState()+`を呼び出してアプリケーションの状態を更新します。

次に、 `+ handleInputchanges()`メソッドの直後に、 ` Create `クラスコンポーネント内で ` render()`メソッドを追加します。 この ` render()+`メソッドは、アプリケーションに新しい顧客を作成するフォームを表示します:

/src/components/customer/Create.tsx

...
 public render() {
     const { submitSuccess, loading } = this.state;
     return (
         <div>
             <div className={"col-md-12 form-wrapper"}>
                 <h2> Create Post </h2>
                 {!submitSuccess && (
                     <div className="alert alert-info" role="alert">
                         Fill the form below to create a new post
                 </div>
                 )}
                 {submitSuccess && (
                     <div className="alert alert-info" role="alert">
                         The form was successfully submitted!
                         </div>
                 )}
                 <form id={"create-post-form"} onSubmit={this.processFormSubmission} noValidate={true}>
                     <div className="form-group col-md-12">
                         <label htmlFor="first_name"> First Name </label>
                         <input type="text" id="first_name" onChange={(e) => this.handleInputChanges(e)} name="first_name" className="form-control" placeholder="Enter customer's first name" />
                     </div>
                     <div className="form-group col-md-12">
                         <label htmlFor="last_name"> Last Name </label>
                         <input type="text" id="last_name" onChange={(e) => this.handleInputChanges(e)} name="last_name" className="form-control" placeholder="Enter customer's last name" />
                     </div>
                     <div className="form-group col-md-12">
                         <label htmlFor="email"> Email </label>
                         <input type="email" id="email" onChange={(e) => this.handleInputChanges(e)} name="email" className="form-control" placeholder="Enter customer's email address" />
                     </div>
                     <div className="form-group col-md-12">
                         <label htmlFor="phone"> Phone </label>
                         <input type="text" id="phone" onChange={(e) => this.handleInputChanges(e)} name="phone" className="form-control" placeholder="Enter customer's phone number" />
                     </div>
                     <div className="form-group col-md-12">
                         <label htmlFor="address"> Address </label>
                         <input type="text" id="address" onChange={(e) => this.handleInputChanges(e)} name="address" className="form-control" placeholder="Enter customer's address" />
                     </div>
                     <div className="form-group col-md-12">
                         <label htmlFor="description"> Description </label>
                         <input type="text" id="description" onChange={(e) => this.handleInputChanges(e)} name="description" className="form-control" placeholder="Enter Description" />
                     </div>
                     <div className="form-group col-md-4 pull-right">
                         <button className="btn btn-success" type="submit">
                             Create Customer
                         </button>
                         {loading &&
                             <span className="fa fa-circle-o-notch fa-spin" />
                         }
                     </div>
                 </form>
             </div>
         </div>
     )
 }
...

ここでは、顧客の + first_name ++ last_name ++ email ++ phone ++ address +、および `+ description `の値を保持する入力フィールドを持つフォームを作成しました。 各入力フィールドには、すべてのキーストロークで実行されるメソッド ` handleInputChanges()`があり、入力フィールドから取得した値でReact ` state `を更新します。 さらに、アプリケーションの状態に応じて、 ` submitSuccess +`という名前のブール変数は、新しい顧客を作成する前後にアプリケーションが表示するメッセージを制御します。

このファイルの完全なコードは、https://github.com/yemiwebby/typescript-react-customer-app/blob/master/src/components/customer/Create.tsx [GitHub repository]で確認できます。

保存して、 `+ Create.tsx +`を終了します。

アプリケーションの `+ Create `コンポーネントファイルに適切なロジックを追加したので、 ` Edit +`コンポーネントファイルのコンテンツを追加します。

+ customer +`フォルダー内の `+ Edit.tsx +`ファイルを開き、次のコンテンツを追加して、 `+ React +、 `+ axios +`をインポートし、TypeScriptインターフェイスを定義します。

/src/components/customer/Edit.tsx

import * as React from 'react';
import { RouteComponentProps, withRouter } from 'react-router-dom';
import axios from 'axios';

export interface IValues {
   [key: string]: any;
}
export interface IFormState {
   id: number,
   customer: any;
   values: IValues[];
   submitSuccess: boolean;
   loading: boolean;
}

`+ Create `コンポーネントと同様に、必要なモジュールをインポートし、それぞれ ` IValues `および ` IFormState `インターフェースを作成します。 ` IValues `インターフェースは入力フィールドの値のデータ型を定義しますが、 ` IFormState +`を使用してアプリケーションの状態オブジェクトの予想される型を宣言します。

次に、以下に示すように、 `+ IFormState `インターフェースブロックの直後に ` EditCustomer +`クラスコンポーネントを作成します。

/src/components/customer/Edit.tsx

...
class EditCustomer extends React.Component<RouteComponentProps<any>, IFormState> {
   constructor(props: RouteComponentProps) {
       super(props);
       this.state = {
           id: this.props.match.params.id,
           customer: {},
           values: [],
           loading: false,
           submitSuccess: false,
       }
   }
}
export default withRouter(EditCustomer)

このコンポーネントは、パラメーターとして「+ RouteComponentProps <any> 」と「 IFormState 」のインターフェースを取ります。 React Routerがパスパラメーターを解析するたびに、データのタイプが「 number 」または「+文字列 `。 お客様の `+ uniqueId `のパラメーターが必要なので、 ` any +`を使用する方が安全です。

コンポーネント内に次のメソッドを追加します。

/src/components/customer/Edit.tsx

...
























...
}

export default withRouter(EditCustomer)

まず、 `+ componentDidMount()`メソッドを追加します。これは、コンポーネントの作成時に呼び出されるライフサイクルメソッドです。 このメソッドは、ルートパラメーターから取得した「 id +」を使用して特定の顧客をパラメーターとして識別し、それを使用してデータベースから詳細を取得し、フォームにそれを入力します。 さらに、フォームの送信を処理するメソッドを追加し、入力フィールドの値に加えられた変更を処理します。

最後に、 `+ Edit `コンポーネントに ` render()+`メソッドを追加します:

/src/components/customer/Edit.tsx

...
   public render() {
       const { submitSuccess, loading } = this.state;
       return (
           <div className="App">
               {this.state.customer &&
                   <div>
                       < h1 > Customer List Management App</h1>
                       <p> Built with React.js and TypeScript </p>

                       <div>
                           <div className={"col-md-12 form-wrapper"}>
                               <h2> Edit Customer </h2>
                               {submitSuccess && (
                                   <div className="alert alert-info" role="alert">
                                       Customer's details has been edited successfully </div>
                               )}
                               <form id={"create-post-form"} onSubmit={this.processFormSubmission} noValidate={true}>
                                   <div className="form-group col-md-12">
                                       <label htmlFor="first_name"> First Name </label>
                                       <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" />
                                   </div>
                                   <div className="form-group col-md-12">
                                       <label htmlFor="last_name"> Last Name </label>
                                       <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" />
                                   </div>
                                   <div className="form-group col-md-12">
                                       <label htmlFor="email"> Email </label>
                                       <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" />
                                   </div>
                                   <div className="form-group col-md-12">
                                       <label htmlFor="phone"> Phone </label>
                                       <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" />
                                   </div>
                                   <div className="form-group col-md-12">
                                       <label htmlFor="address"> Address </label>
                                       <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" />
                                   </div>
                                   <div className="form-group col-md-12">
                                       <label htmlFor="description"> Description </label>
                                       <input type="text" id="description" defaultValue={this.state.customer.description} onChange={(e) => this.handleInputChanges(e)} name="description" className="form-control" placeholder="Enter Description" />
                                   </div>
                                   <div className="form-group col-md-4 pull-right">
                                       <button className="btn btn-success" type="submit">
                                           Edit Customer </button>
                                       {loading &&
                                           <span className="fa fa-circle-o-notch fa-spin" />
                                       }
                                   </div>
                               </form>
                           </div>
                       </div>
                   </div>
               }
           </div>
       )
   }
...

ここでは、特定の顧客の詳細を編集するフォームを作成し、そのフォーム内の入力フィールドに、アプリケーションの状態が取得した顧客の詳細を入力しました。 `+ Create `コンポーネントと同様に、すべての入力フィールドに加えられた変更は ` handleInputChanges()+`メソッドによって処理されます。

このファイルの完全なコードは、https://github.com/yemiwebby/typescript-react-customer-app/blob/master/src/components/customer/Edit.tsx [GitHub repository]で確認できます。

保存して、 `+ Edit.tsx +`を終了します。

アプリケーション内で作成された顧客の完全なリストを表示するには、「。/ src / components +」フォルダー内に新しいコンポーネントを作成し、「 Home.tsx +」という名前を付けます。

cd ./src/components
nano Home.tsx

次のコンテンツを追加します。

/src/components/Home.tsx

import * as React from 'react';
import { Link, RouteComponentProps } from 'react-router-dom';
import axios from 'axios';

interface IState {
   customers: any[];
}

export default class Home extends React.Component<RouteComponentProps, IState> {
   constructor(props: RouteComponentProps) {
       super(props);
       this.state = { customers: [] }
   }
   public componentDidMount(): void {
       axios.get(`http://localhost:5000/customers`).then(data => {
           this.setState({ customers: data.data })
       })
   }
   public deleteCustomer(id: number) {
       axios.delete(`http://localhost:5000/customers/${id}`).then(data => {
           const index = this.state.customers.findIndex(customer => customer.id === id);
           this.state.customers.splice(index, 1);
           this.props.history.push('/');
       })
   }
}

ここでは、React Routerから「+ React 」、「 axios 」、およびその他の必要なコンポーネントをインポートしました。 ` Home +`コンポーネント内に2つの新しいメソッドを作成しました:

  • + componentDidMount()+:アプリケーションは、コンポーネントがマウントされた直後にこのメソッドを呼び出します。 ここでの責任は、顧客のリストを取得し、それでホームページを更新することです。

  • + deleteCustomer()+:このメソッドは、パラメーターとして `+ id `を受け入れ、その ` id +`で識別される顧客の詳細をデータベースから削除します。

ここで、 `+ Home `コンポーネントの顧客のリストを保持するテーブルを表示するために、 ` render()+`メソッドを追加します。

/src/components/Home.tsx

...
public render() {
       const customers = this.state.customers;
       return (
           <div>
               {customers.length === 0 && (
                   <div className="text-center">
                       <h2>No customer found at the moment</h2>
                   </div>
               )}
               <div className="container">
                   <div className="row">
                       <table className="table table-bordered">
                           <thead className="thead-light">
                               <tr>
                                   <th scope="col">Firstname</th>
                                   <th scope="col">Lastname</th>
                                   <th scope="col">Email</th>
                                   <th scope="col">Phone</th>
                                   <th scope="col">Address</th>
                                   <th scope="col">Description</th>
                                   <th scope="col">Actions</th>
                               </tr>
                           </thead>
                           <tbody>
                               {customers && customers.map(customer =>
                                   <tr key={customer.id}>
                                       <td>{customer.first_name}</td>
                                       <td>{customer.last_name}</td>
                                       <td>{customer.email}</td>
                                       <td>{customer.phone}</td>
                                       <td>{customer.address}</td>
                                       <td>{customer.description}</td>
                                       <td>
                                           <div className="d-flex justify-content-between align-items-center">
                                               <div className="btn-group" style={{ marginBottom: "20px" }}>
                                                   <Link to={`edit/${customer.id}`} className="btn btn-sm btn-outline-secondary">Edit Customer </Link>
                                                   <button className="btn btn-sm btn-outline-secondary" onClick={() => this.deleteCustomer(customer.id)}>Delete Customer</button>
                                               </div>
                                           </div>
                                       </td>
                                   </tr>
                               )}
                           </tbody>
                       </table>
                   </div>
               </div>
           </div>
       )
   }
...

このコードブロックでは、アプリケーションの状態から顧客のリストを配列として取得し、それを反復処理して、HTMLテーブル内に表示します。 また、メソッドがリストから特定の顧客の詳細を識別および削除するために使用する「+ customer.id +」パラメーターも追加します。

保存して、 `+ Home.tsx +`を終了します。

インターフェースを使用してコンポーネントとプロップのタイプを定義することにより、このアプリケーションで作成されたすべてのコンポーネントに対して静的に型付けされた原則を採用しました。 これは、ReactアプリケーションでTypeScriptを使用するための最良のアプローチの1つです。

これで、アプリケーションに必要なすべての再利用可能なコンポーネントの作成が完了しました。 これで、これまでに作成したすべてのコンポーネントへのリンクでアプリコンポーネントを更新できます。

手順4-ルーティングの設定とアプリケーションのエントリポイントの更新

このステップでは、React Routerパッケージから必要なコンポーネントをインポートし、ロードされるルートに応じて異なるコンポーネントをレンダリングするように「+ App 」コンポーネントを設定します。 これにより、アプリケーションのさまざまなページをナビゲートできます。 ユーザーが「 / create +」などのルートにアクセスすると、React Routerは指定されたパスを使用して、そのルートを処理するために定義された適切なコンポーネント内のコンテンツとロジックをレンダリングします。

`+。/ src / App.tsx +`に移動します:

nano App.tsx

次に、そのコンテンツを次のものに置き換えます。

/src/App.tsx

import * as React from 'react';
import './App.css';
import { Switch, Route, withRouter, RouteComponentProps, Link } from 'react-router-dom';
import Home from './components/Home';
import Create from './components/customer/Create';
import EditCustomer from './components/customer/Edit';

class App extends React.Component<RouteComponentProps<any>> {
 public render() {
   return (
     <div>
       <nav>
         <ul>
           <li>
             <Link to={'/'}> Home </Link>
           </li>
           <li>
             <Link to={'/create'}> Create Customer </Link>
           </li>
         </ul>
       </nav>
       <Switch>
         <Route path={'/'} exact component={Home} />
         <Route path={'/create'} exact component={Create} />
         <Route path={'/edit/:id'} exact component={EditCustomer} />
       </Switch>
     </div>
   );
 }
}
export default withRouter(App);

React Routerパッケージから必要なすべてのコンポーネントをインポートし、顧客の詳細を作成、編集、表示するための再利用可能なコンポーネントもインポートしました。

保存して `+ App.tsx +`を終了します。

`。/ src / index.tsx +`ファイルはこのアプリケーションのエントリポイントであり、アプリケーションをレンダリングします。 このファイルを開き、React Routerをインポートしてから、 ` App `コンポーネントを ` BrowserRouter +`内にラップします。

/src/index.tsx

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

import * as serviceWorker from './serviceWorker';
ReactDOM.render(

       <App />

   , document.getElementById('root')
);
serviceWorker.unregister();

React Routerは、 `+ BrowserRouter +`コンポーネントを使用して、履歴や現在のパスなどのナビゲーションをアプリケーションに認識させます。

「+ Index.tsx +」の編集が完了したら、保存して終了します。

最後に、Bootstrapを使用して、アプリケーションにスタイルを追加します。 Bootstrapは、Web上でレスポンシブなモバイルファーストプロジェクトを開発するための一般的なHTML、CSS、およびJavaScriptフレームワークです。 開発者は、CSSを大量に記述することなく、魅力的なユーザーインターフェイスを構築できます。 レスポンシブグリッドシステムが付属しており、すべてのデバイスで機能するWebページを完成した外観にします。

アプリケーションにブートストラップとスタイリングを含めるには、 `+。/ src / App.css`の内容を次のものに置き換えます。

/src/App.css

@import 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css';

.form-wrapper {
 width: 500px;
 margin: 0 auto;
}
.App {
 text-align: center;
 margin-top: 30px;
}
nav {
 width: 300px;
 margin: 0 auto;
 background: #282c34;
 height: 70px;
 line-height: 70px;
}
nav ul li {
 display: inline;
 list-style-type: none;
 text-align: center;
 padding: 30px;
}
nav ul li a {
 margin: 50px 0;
 font-weight: bold;
 color: white;
 text-decoration: none;
}
nav ul li a:hover {
 color: white;
 text-decoration: none;
}
table {
 margin-top: 50px;
}
.App-link {
 color: #61dafb;
}
@keyframes App-logo-spin {
 from {
   transform: rotate(0deg);
 }
 to {
   transform: rotate(360deg);
 }
}

ここでBootstrapを使用して、デフォルトのレイアウト、スタイル、色を指定することにより、アプリケーションのルックアンドフィールを向上させました。 また、特にナビゲーションバーにいくつかのカスタムスタイルを追加しました。

保存して `+ App.css`を終了します。

このセクションでは、ユーザーがアクセスしたルートに応じて適切なコンポーネントを表示するようにReact Routerを構成し、ユーザーにとってアプリケーションをより魅力的にするためのスタイリングを追加しました。 次に、アプリケーションに実装されているすべての機能をテストします。

ステップ5-アプリケーションの実行

いくつかの再利用可能なコンポーネントを作成して、ReactとTypeScriptでこのアプリケーションのフロントエンドを設定し、 `+ json-server +`でREST APIを構築したので、アプリを実行できます。

プロジェクトのルートフォルダーに戻ります。

cd ~/typescript-react-app

次に、次のコマンドを実行してアプリを起動します。

yarn start

`+ http:// localhost:3000 +`に移動して、ブラウザからアプリケーションを表示します。 次に、[作成]ボタンをクリックして、顧客の詳細を入力します。

image:https://assets.digitalocean.com/articles/reacttypescript/step5a.png [顧客ページの作成]

入力フィールドに適切な値を入力したら、[顧客の作成]ボタンをクリックしてフォームを送信します。 新しい顧客の作成が完了すると、アプリケーションによってホームページにリダイレクトされます。

image:https://assets.digitalocean.com/articles/reacttypescript/step5b.png [顧客ページを表示]

行の[*顧客の編集]ボタンをクリックすると、その行の対応する顧客の編集機能をホストするページに移動します。

image:https://assets.digitalocean.com/articles/reacttypescript/step5c.png [顧客ページの編集]

顧客の詳細を編集し、[顧客の編集]をクリックして顧客の詳細を更新します。

アプリケーションを実行して、すべてのコンポーネントが機能していることを確認しました。 アプリケーションのさまざまなページを使用して、顧客エントリを作成および編集しました。

結論

このチュートリアルでは、https://reactjs.org/ [React]およびhttps://www.typescriptlang.org/[TypeScript]を使用して顧客リスト管理アプリを作成しました。 このチュートリアルのプロセスは、Reactを使用してアプリケーションを構築および構築する従来の方法としてJavaScriptを使用することとは異なります。 TypeScriptを使用する利点を活用して、このフロントエンドに焦点を当てたチュートリアルを完了しました。

このプロジェクトの開発を続けるには、モックバックエンドサーバーを、https://expressjs.com/ [Express]やhttps://nestjs.com/[Nest.jsなどの本番対応のバックエンドテクノロジーに移行できます。 ]。 さらに、http://www.passportjs.org/ [Passport.js]認証ライブラリなどのさまざまなツールを使用して認証や承認などの機能を追加することにより、このチュートリアルで作成したものを拡張できます。

プロジェクトhttps://github.com/yemiwebby/typescript-react-customer-app[GitHub]の完全なソースコードを見つけることができます。