目次
前回のあらすじ
前回、登録ボタンを押すと、フォームに入力したタイトルと本文がアラートに表示されるようにしました。

今回は、タイトルと本文をTodoコンポーネントの配列に追加して、さらにこの配列でTodoListコンポーネントを更新するところまでを行います。
前回は主にStateを使いましたが、今回はPropsの使い方の話になります。
というわけで、前回のソースコード を元に話を進めます。
準備
TODOリストのデータはTodoコンポーネントのStateで配列として保持することにします。
そのためにまず、1件のTODOデータを扱うオブジェクトのインタフェースTodoDataを定義します。
TodoDataインタフェース
この定義はTodoコンポーネントだけではなくTodoListコンポーネントとTodoItemコンポーネントでも利用するので、Todo.tsxに定義するのではなく別ファイルTodoData.tsxを用意してから、Todo.tsxとTodoList.tsxにインポートして利用します。
TodoData.tsx
export interface TodoData {
id: number;
title: string;
content: string;
date: string;
time: string;
}
タイトルと本文だけではなく、IDと更新日時もTodoDataで扱うようにします。
Todo.tsx および TodoList.tsx、TodoItem.tsx では、以下の1文を加えてインポートしてください。
import { TodoData } from './TodoData';
TodoコンポーネントのPropsとState
次に前回同様、TodoコンポーネントにPropsとStateのインタフェースを定義して、コンストラクタで初期化します。
Todo.tsx
// Propsインタフェース
interface TodoPropsInterface {
}
// Stateインタフェース
interface TodoStateInterface {
todoData: TodoData[];
idCount: number;
}
class Todo extends React.Component<TodoPropsInterface, TodoStateInterface> {
public constructor(props:TodoPropsInterface) {
super(props);
this.state = {
todoData: [],
idCount: 0,
};
}
StateのメンバtodoDataがTODOデータの格納配列、idCountはIDの配番に使うカウンタです。
クリックリスナの引き上げ
前回、登録ボタンを押すとTodoEditコンポーネントのonClick_Submit()メソッドが呼ばれるようにしました。しかし、このメソッドではTODOデータの格納先であるTodoコンポーネントのStateにアクセスできません。
そこで、onClick_Submit()メソッドをTodoコンポーネントに引き上げます。
ざっくりと処理の流れを説明するとこんな感じです。
TodoコンポーネントにonClick_Submit()メソッドを用意する。TodoコンポーネントからTodoEditコンポーネントのPropsにonClick_Submit()メソッドをわたす。TodoEditコンポーネントは、登録ボタンが押されたら、PropsのonClick_Submit()メソッドを呼ぶ。TodoコンポーネントのonClick_SubmitメソッドでTODOデータを配列に追加する。
この手順に従って実装を進めてみましょう。
onClick_Submit()メソッドを用意する
まず、TodoコンポーネントonClick_Submit()メソッドを用意します。
内容は以下のとおりです。タイトルと本文を受け取って、それを元にTodoDataオブジェクトを作成して配列todoDataに追加する。ついでにidCountを進めています。
Stateを変更する場合は、Stateのメンバ変数を直接変更するのではなくて、必ずsetState()メソッドを使うことに注意してください。
Todo.tsx
// クリック:登録
private onClick_Submit(title:string, content:string) {
if (title == '' || content == '') {
alert("タイトルと本文を入力してください。");
return;
}
// 日時文字列作成
let date = new Date();
let dateStr = date.getFullYear() + "/" + (date.getMonth() + 1) + "/" + date.getDate();
let timeStr = date.getHours() + ":" + date.getMinutes() + ":" + date.getUTCSeconds();
// Todoデータ追加
let todoData = this.state.todoData.slice();
todoData.push({
id: this.state.idCount,
title: title,
content: content,
date: dateStr,
time: timeStr,
});
this.setState({
todoData: todoData,
idCount: this.state.idCount + 1,
});
}
PropsにonClick_Submit()メソッドを加える
TodoEditコンポーネントのPropsにonClick_Submit()メソッドを追加します。
最後のvoidはonClick_Submit()メソッドの戻り値の型です。今回は何も返さないのでvoidです。
TodoEdit.tsx
// Propsインタフェース
interface TodoEditPropsInterface {
onClick_Submit(title:string, content:string):void;
}
TodoEditコンポーネントのPropsにonClick_Submit()メソッドを追加すると、VisualStudioCodeでは以下のように、render()メソッドでTodoEditコンポーネントがエラーになります。
「TodoEditコンポーネントはPropsにonClick_Submit()メソッドを必要としているのに、それが与えられていない」という警告です。

というわけで与えてやります。
Todo.tsx
// 描画
public render() {
return (
<div>
<TodoEdit onClick_Submit={(t, c) => this.onClick_Submit(t, c)}/>
<TodoList />
</div>
);
}
PropsのonClick_Submit()メソッドを呼ぶ
TodoEditコンポーネントのonClick_Submit()メソッドは不要になったので削除します。
登録ボタンではPropsのonClick_Submit()メソッドを呼びます。引数のタイトルと本文はTodoEditコンポーネントのStateから渡します。
TodoEdit.tsx
// クリック:登録
// private onClick_Submit() {
// alert(this.state.title + " " + this.state.content);
// }
…
<div>
<button>新規</button>
<button onClick={() => this.props.onClick_Submit(this.state.title, this.state.content)} >登録</button>
</div>
TODOデータを配列に追加する
これは前述のonClick_Submit()メソッドのコードの通りです。
TODOリストの表示
配列にTODOデータを追加できるようになりました。ただこれでは内部データに追加されただけなので確認ができません。
そこで次は、TODOデータ配列をTODOリストに表示できるようにします。
ここでもやはりPropsを利用してTodo → TodoList → TodoItemの各コンポーネントへとデータを渡します。
TodoListコンポーネントのProps(とState)
TodoListコンポーネントのPropsにはTodoDataの配列を追加します。
TodoList.tsx
import {TodoData} from './TodoData';
// Propsインタフェース
interface TodoListPropsInterface {
todoData:TodoData[];
}
// Stateインタフェース
interface TodoListStateInterface {
}
class TodoList extends React.Component<TodoListPropsInterface, TodoListStateInterface> {
TodoItemコンポーネントのProps(とState)
TodoItemコンポーネントは1件のTODOデータを扱うだけなので、PropsにはTodoDataをひとつ追加します。
TodoItem.tsx
import {TodoData} from './TodoData';
// Propsインタフェース
interface TodoItemPropsInterface {
todoData: TodoData;
}
// Stateインタフェース
interface TodoItemStateInterface {
}
class TodoItem extends React.Component<TodoItemPropsInterface, TodoItemStateInterface> {
TODOデータの表示
あとは上から順にデータを渡して、TodoItemコンポーネントで表示するだけです。
まずTodoコンポーネントからTodoListコンポーネントへTODOデータ配列を渡します。
Todo.tsx
// 描画
public render() {
return (
<div>
<TodoEdit onClick_Submit={(t, c) => this.onClick_Submit(t, c)}/>
<TodoList todoData={this.state.todoData} />
</div>
);
}
次に、TodoListコンポーネントからTodoItemコンポーネントへTODOデータをひとつずつ渡します。
JSX内でループすることができないので、まずitemsを組み立ててからJSXに組み込んでいる点に注目してください。
TodoList.tsx
// 描画
render() {
const items = this.props.todoData.map((d) => {
return <TodoItem todoData={d} />;
});
return (
<div>
<table className='todo-table'>
<tr>
<th>タイトル</th>
<th>本文</th>
<th>日付</th>
<th>時刻</th>
<th></th>
<th></th>
</tr>
{items}
</table>
</div>
)
}
最後にTodoItemコンポーネントでの表示部分の修正です。
TodoItem.tsx
// 描画
render() {
return (
<tr>
<td>{this.props.todoData.title}</td>
<td>{this.props.todoData.content}</td>
<td>{this.props.todoData.date}</td>
<td>{this.props.todoData.time}</td>
<td><button>編集</button></td>
<td><button>削除</button></td>
</tr>
);
}
次回に続く
今回はここまでです。
TODOリストに行を追加できるようになりました。

ここまでの ソースコード です。
次回は編集ボタンと新規ボタンの動作を実装して、この一連の記事を締め括りたいと思います。
