ReactとTypeScriptを使用して顧客リスト管理アプリを構築する方法
著者は、 Write forDOnationsプログラムの一環として寄付を受け取るためにTechEducationFundを選択しました。
序章
TypeScript は、 JavaScript 開発者がアプリ、特にWebアプリケーションのコードを構造化および作成する方法に多くの改善をもたらしました。 JavaScriptのスーパーセットとして定義されたTypeScriptは、JavaScriptと同じように動作しますが、開発者がバグの少ない、またはバグのない、より大きく複雑なプログラムを構築できるように設計された追加機能を備えています。 TypeScriptはますます人気が高まっています。 AngularWebフレームワークのためにGoogleのような主要企業によって採用されました。 Nest.jsバックエンドフレームワークもTypeScriptで構築されました。
開発者としての生産性を向上させる方法の1つは、本番環境で既存のアプリを壊すことを心配せずに、新しい機能をできるだけ早く実装できることです。 これを実現するために、静的に型付けされたコードを書くことは、多くのベテラン開発者によって採用されているスタイルです。 TypeScriptのような静的に型付けされたプログラミング言語は、すべての変数とデータ型の関連付けを強制します。 文字列、整数、ブール値など。 静的に型付けされたプログラミング言語を使用する主な利点の1つは、型チェックがコンパイル時に完了するため、開発者は非常に早い段階でコードのエラーを確認できることです。
React はオープンソースのJavaScriptライブラリであり、開発者はこれを使用して、スケーラブルなWebアプリケーション用のハイエンドユーザーインターフェイスを作成します。 単一ページアプリケーション用にReactで構築された優れたパフォーマンスと動的なユーザーインターフェイスにより、開発者の間で人気のある選択肢となっています。
このチュートリアルでは、個別のREST APIバックエンドと、ReactおよびTypeScriptで構築されたフロントエンドを使用して顧客リスト管理アプリケーションを作成します。 json-serverという名前の偽のRESTAPIを使用してバックエンドを構築します。 これを使用して、CRUD(作成、読み取り、更新、および削除)バックエンドをすばやく設定します。 したがって、ReactとTypeScriptを使用してアプリケーションのフロントエンドロジックの処理に集中できます。
前提条件
このチュートリアルを完了するには、次のものが必要です。
-
Node.js (少なくともv6)および npm (少なくともv5.2)のローカルインストール。 Node.jsは、ブラウザの外部でコードを実行できるJavaScriptランタイム環境です。
npm
と呼ばれるパッケージマネージャーがプリインストールされており、パッケージをインストールおよび更新できます。 これらをmacOSまたはUbuntu18.04にインストールするには、Node.jsをインストールしてmacOSにローカル開発環境を作成する方法またはノードをインストールする方法の「PPAを使用してインストールする」セクションの手順に従います。 Ubuntu18.04の.js。 -
Yarnのローカルインストール。 次の手順に従って、オペレーティングシステムにYarnをインストールします。
-
TypeScriptとJavaScriptの基本的な理解。
-
インストールされたテキストエディタ。 Visual Studio Code 、 Atom 、 SublimeTextなど。
ステップ1—TypeScriptのインストールとReactアプリケーションの作成
このステップでは、ノードパッケージマネージャー(npm
)を使用して、TypeScriptパッケージをマシンにグローバルにインストールします。 その後、Reactとその依存関係もインストールし、開発サーバーを実行してReactアプリが機能していることを確認します。
まず、ターミナルを開き、次のコマンドを実行してTypeScriptをインストールします。
- npm install -g typescript
インストールプロセスが完了したら、次のコマンドを実行して、TypeScriptのインストールを確認します。
- tsc -v
マシンにインストールされている現在のバージョンが表示されます。
OutputVersion 3.4.5
次に、 create-react-app ツールを使用してReactアプリケーションをインストールし、1つのコマンドでアプリケーションをセットアップします。 npx
コマンドを使用します。これは、npm
5.2以降に付属するパッケージランナーツールです。 create-react-app
ツールには、追加の構成を必要とせずにTypeScriptを操作するためのサポートが組み込まれています。 次のコマンドを実行して、typescript-react-app
という名前の新しいReactアプリケーションを作成してインストールします。
- npx create-react-app typescript-react-app --typescript
上記のコマンドは、typescript-react-app
という名前の新しいReactアプリケーションを作成します。 --typescript
フラグは、Reactコンポーネントのデフォルトのファイルタイプを.tsx
に設定します。
このセクションを完了する前に、アプリケーションは1つのポートから別のポートに移動する必要があります。 これを行うには、 ReactRouterという名前のReactアプリケーション用のルーティングライブラリとそれに対応するTypeScript定義をインストールする必要があります。 yarn
を使用して、このプロジェクトのライブラリとその他のパッケージをインストールします。 これは、特にReactアプリケーションの依存関係をインストールする場合に、yarn
の方が高速であるためです。 新しく作成したプロジェクトフォルダーに移動し、次のコマンドを使用してReactRouterをインストールします。
- cd typescript-react-app
- yarn add react-router-dom
これで、プロジェクト内のルーティング機能を提供するReactRouterパッケージができました。 次に、次のコマンドを実行して、ReactRouterのTypeScript定義をインストールします。
- yarn add @types/react-router-dom
次に、ブラウザ用のPromisedベースのHTTPクライアントである axios をインストールして、アプリケーション内で作成するさまざまなコンポーネントからHTTPリクエストを実行するプロセスを支援します。
- yarn add axios
インストールプロセスが完了したら、次のコマンドで開発サーバーを起動します。
- yarn start
アプリケーションはhttp://localhost:3000
で実行されます。
これで、TypeScriptが正常にインストールされ、新しいReactアプリケーションが作成され、アプリケーションのあるページから別のページへの移動を支援するためにReactRouterがインストールされました。 次のセクションでは、アプリケーションのバックエンドサーバーを設定します。
ステップ2—JSONサーバーを作成する
このステップでは、Reactアプリケーションがすばやく接続し、そのリソースを使用できる模擬サーバーを作成します。 このバックエンドサービスは、本番環境のアプリケーションには適していないことに注意してください。 Nest.js、Express、またはその他のバックエンドテクノロジーを使用して、本番環境でRESTfulAPIを構築できます。 json-server
は、プロトタイプを作成してバックエンドサーバーをモックする必要がある場合に便利なツールです。
npm
またはyarn
のいずれかを使用して、json-server
をマシンにインストールできます。 これにより、プロジェクトを使用する必要がある場合はいつでも、プロジェクトの任意のディレクトリから利用できるようになります。 新しいターミナルウィンドウを開き、次のコマンドを実行して、プロジェクトディレクトリ内にいる間にjson-server
をインストールします。
- yarn global add json-server
次に、RESTAPIによって公開されるデータを含むJSONファイルを作成します。 このファイル(作成する)で指定されたオブジェクトの場合、CRUDエンドポイントが自動的に生成されます。 まず、server
という名前の新しいフォルダーを作成し、そのフォルダーに移動します。
- mkdir server
- cd server
次に、nano
を使用して、db.json
という名前の新しいファイルを作成して開きます。
- nano 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
、および7つのプロパティで構成されます。 address
。
ファイルを保存して終了します。
デフォルトでは、json-server
はポート3000
で実行されます。これは、Reactアプリケーションが実行されるのと同じポートです。 競合を回避するために、json-server
のデフォルトポートを変更できます。 これを行うには、アプリケーションのルートディレクトリに移動します。
- cd ~/typescript-react-app
お好みのテキストエディタでアプリケーションを開き、json-server.json
という名前の新しいファイルを作成します。
- nano json-server.json
次に、以下を挿入してポート番号を更新します。
{
"port": 5000
}
これはjson-server
の構成ファイルとして機能し、サーバーが常に指定されたポートで実行されるようにします。
ファイルを保存して終了します。
サーバーを実行するには、次のコマンドを使用します。
- json-server --watch server/db.json
これにより、ポート5000
でjson-server
が開始されます。 ブラウザでhttp://localhost:5000/customers
に移動すると、サーバーに顧客リストが表示されます。
json-server
の実行プロセスを合理化するために、package.json
をserver
という名前の新しいプロパティでscripts
オブジェクトに更新できます。
{
...
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"server": "json-server --watch server/db.json"
},
...
}
ファイルを保存して終了します。
これで、json-server
を起動したいときはいつでも、ターミナルからyarn server
を実行するだけです。
このアプリケーションのバックエンドサーバーとして使用する単純なRESTAPIを作成しました。 また、RESTAPIのデフォルトデータとして使用されるカスタマー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
ファイルを開き、次のコードを追加します。
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
、およびルーティングに必要なその他の必要なコンポーネントをReactRouterパッケージからインポートしました。 その後、IValues
とIFormState
という名前の2つの新しいインターフェイスを作成しました。 TypeScriptインターフェイスは、オブジェクトに渡す必要のある特定のタイプの値を定義し、アプリケーション全体で一貫性を保つのに役立ちます。 これにより、プログラムにバグが発生する可能性が低くなります。
次に、React.Component
を拡張するCreate
コンポーネントを作成します。 IFormState
インターフェースの直後の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
クラスコンポーネント内にこれらのメソッドを追加します。 これらのメソッドを使用して、顧客フォームを処理し、入力フィールドのすべての変更を処理します。
...
values: [],
loading: false,
submitSuccess: false,
}
}
private processFormSubmission = (e: React.FormEvent<HTMLFormElement>): void => {
e.preventDefault();
this.setState({ loading: true });
const formData = {
first_name: this.state.first_name,
last_name: this.state.last_name,
email: this.state.email,
phone: this.state.phone,
address: this.state.address,
description: this.state.description,
}
this.setState({ submitSuccess: true, values: [...this.state.values, formData], loading: false });
axios.post(`http://localhost:5000/customers`, formData).then(data => [
setTimeout(() => {
this.props.history.push('/');
}, 1500)
]);
}
private handleInputChanges = (e: React.FormEvent<HTMLInputElement>) => {
e.preventDefault();
this.setState({
[e.currentTarget.name]: e.currentTarget.value,
})
}
...
export default withRouter(Create)
...
processFormSubmission()
メソッドは、アプリケーションの状態から顧客の詳細を受け取り、axios
を使用してデータベースに投稿します。 handleInputChanges()
は、React.FormEvent
を使用してすべての入力フィールドの値を取得し、this.setState()
を呼び出してアプリケーションの状態を更新します。
次に、handleInputchanges()
メソッドの直後のCreate
クラスコンポーネント内にrender()
メソッドを追加します。 このrender()
メソッドは、アプリケーションで新しい顧客を作成するためのフォームを表示します。
...
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()
があり、入力フィールドから取得した値でReactstate
を更新します。 さらに、アプリケーションの状態に応じて、submitSuccess
という名前のブール変数が、新しい顧客を作成する前後にアプリケーションが表示するメッセージを制御します。
このファイルの完全なコードは、このGitHubリポジトリで確認できます。
Create.tsx
を保存して終了します。
アプリケーションのCreate
コンポーネントファイルに適切なロジックを追加したので、次にEdit
コンポーネントファイルのコンテンツを追加します。
customer
フォルダー内のEdit.tsx
ファイルを開き、次のコンテンツを追加してReact
、axios
をインポートし、TypeScriptインターフェイスを定義します。
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
クラスコンポーネントを作成します。
...
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
のインターフェースをパラメーターとして受け取ります。 <any>
をRouteComponentProps
に追加することを使用します。これは、React Routerがパスパラメーターを解析するたびに、データのタイプがnumber
であるかどうかを確認するためのタイプ変換を行わないためです。またはstring
。 顧客のuniqueId
のパラメーターを期待しているので、any
を使用する方が安全です。
次に、コンポーネント内に次のメソッドを追加します。
...
public componentDidMount(): void {
axios.get(`http://localhost:5000/customers/${this.state.id}`).then(data => {
this.setState({ customer: data.data });
})
}
private processFormSubmission = async (e: React.FormEvent<HTMLFormElement>): Promise<void> => {
e.preventDefault();
this.setState({ loading: true });
axios.patch(`http://localhost:5000/customers/${this.state.id}`, this.state.values).then(data => {
this.setState({ submitSuccess: true, loading: false })
setTimeout(() => {
this.props.history.push('/');
}, 1500)
})
}
private setValues = (values: IValues) => {
this.setState({ values: { ...this.state.values, ...values } });
}
private handleInputChanges = (e: React.FormEvent<HTMLInputElement>) => {
e.preventDefault();
this.setValues({ [e.currentTarget.id]: e.currentTarget.value })
}
...
}
export default withRouter(EditCustomer)
まず、componentDidMount()
メソッドを追加します。これは、コンポーネントの作成時に呼び出されるライフサイクルメソッドです。 このメソッドは、ルートパラメーターから取得したid
を取得して特定の顧客をパラメーターとして識別し、それを使用してデータベースから詳細を取得し、フォームに入力します。 さらに、フォームの送信を処理し、入力フィールドの値に加えられた変更を処理するメソッドを追加します。
最後に、Edit
コンポーネントにrender()
メソッドを追加します。
...
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()
メソッドによって処理されます。
このファイルの完全なコードは、このGitHubリポジトリで確認できます。
Edit.tsx
を保存して終了します。
アプリケーション内で作成された顧客の完全なリストを表示するには、./src/components
フォルダー内に新しいコンポーネントを作成し、Home.tsx
という名前を付けます。
- cd ./src/components
- nano 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
、axios
、およびその他の必要なコンポーネントをReactRouterからインポートしました。 Home
コンポーネント内に2つの新しいメソッドを作成しました。
componentDidMount()
:アプリケーションは、コンポーネントがマウントされた直後にこのメソッドを呼び出します。 ここでの責任は、顧客のリストを取得し、それを使用してホームページを更新することです。deleteCustomer()
:このメソッドは、id
をパラメーターとして受け入れ、そのid
で識別される顧客の詳細をデータベースから削除します。
次に、render()
メソッドを追加して、Home
コンポーネントの顧客のリストを保持するテーブルを表示します。
...
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
次に、その内容を次のように置き換えます。
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
内にラップします。
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { BrowserRouter } from 'react-router-dom';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>
, document.getElementById('root')
);
serviceWorker.unregister();
React Routerは、BrowserRouter
コンポーネントを使用して、履歴や現在のパスなどのナビゲーションをアプリケーションに認識させます。
Index.tsx
の編集が終了したら、保存して終了します。
最後に、Bootstrapを使用して、アプリケーションにスタイルを追加します。 Bootstrap は、レスポンシブなモバイルファーストプロジェクトをWeb上で開発するための、人気のあるHTML、CSS、およびJavaScriptフレームワークです。 これにより、開発者は、CSSをあまり記述しなくても、魅力的なユーザーインターフェイスを構築できます。 レスポンシブグリッドシステムが付属しており、すべてのデバイスで機能する仕上がりの外観をWebページに提供します。
アプリケーションにブートストラップとスタイリングを含めるには、./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
を使用してRESTAPIを構築したので、アプリを実行できます。
プロジェクトのルートフォルダに戻ります。
- cd ~/typescript-react-app
次に、次のコマンドを実行してアプリを起動します。
- yarn start
注:サーバーが他のターミナルウィンドウでまだ実行されていることを確認してください。 それ以外の場合は、yarn server
で開始します。
http://localhost:3000
に移動して、ブラウザーからアプリケーションを表示します。 次に、作成ボタンをクリックして、顧客の詳細を入力します。
入力フィールドに適切な値を入力した後、顧客の作成ボタンをクリックしてフォームを送信します。 新しい顧客の作成が完了すると、アプリケーションはホームページにリダイレクトします。
いずれかの行の顧客の編集ボタンをクリックすると、その行の対応する顧客の編集機能をホストするページに移動します。
顧客の詳細を編集し、顧客の編集をクリックして顧客の詳細を更新します。
アプリケーションを実行して、すべてのコンポーネントが機能していることを確認しました。 アプリケーションのさまざまなページを使用して、顧客エントリを作成および編集しました。
結論
このチュートリアルでは、ReactとTypeScriptを使用して顧客リスト管理アプリを作成しました。 このチュートリアルのプロセスは、Reactを使用してアプリケーションを構造化および構築する従来の方法としてJavaScriptを使用することとは異なります。 TypeScriptを使用する利点を活用して、このフロントエンドに焦点を当てたチュートリアルを完了しました。
このプロジェクトの開発を継続するには、モックバックエンドサーバーをExpressやNest.jsなどの本番環境に対応したバックエンドテクノロジーに移行できます。 さらに、 Passport.js 認証ライブラリなどのさまざまなツールを使用して認証や承認などの機能を追加することにより、このチュートリアルで構築したものを拡張できます。
プロジェクトの完全なソースコードはGitHubにあります。