目次
前回のあらすじ
前回、登録ボタンを押すと、フォームに入力したタイトルと本文がアラートに表示されるようにしました。
今回は、タイトルと本文をTodo
コンポーネントの配列に追加して、さらにこの配列でTodoList
コンポーネントを更新するところまでを行います。
前回は主にStateを使いましたが、今回はPropsの使い方の話になります。
というわけで、前回のソースコード を元に話を進めます。
準備
TODOリストのデータはTodo
コンポーネントのStateで配列として保持することにします。
そのためにまず、1件のTODOデータを扱うオブジェクトのインタフェースTodoData
を定義します。
TodoData
インタフェース
この定義はTodo
コンポーネントだけではなくTodoList
コンポーネントとTodoItem
コンポーネントでも利用するので、Todo.tsx
に定義するのではなく別ファイルTodoData.tsx
を用意してから、Todo.tsx
とTodoList.tsx
にインポートして利用します。
TodoData.tsx
1 2 3 4 5 6 7 |
export interface TodoData { id: number; title: string; content: string; date: string; time: string; } |
タイトルと本文だけではなく、IDと更新日時もTodoData
で扱うようにします。
Todo.tsx
および TodoList.tsx
、TodoItem.tsx
では、以下の1文を加えてインポートしてください。
1 |
import { TodoData } from './TodoData'; |
Todo
コンポーネントのPropsとState
次に前回同様、Todo
コンポーネントにPropsとStateのインタフェースを定義して、コンストラクタで初期化します。
Todo.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
// クリック:登録 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
1 2 3 4 |
// Propsインタフェース interface TodoEditPropsInterface { onClick_Submit(title:string, content:string):void; } |
TodoEdit
コンポーネントのPropsにonClick_Submit()
メソッドを追加すると、VisualStudioCodeでは以下のように、render()
メソッドでTodoEdit
コンポーネントがエラーになります。
「TodoEdit
コンポーネントはPropsにonClick_Submit()
メソッドを必要としているのに、それが与えられていない」という警告です。
というわけで与えてやります。
Todo.tsx
1 2 3 4 5 6 7 8 9 |
// 描画 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
1 2 3 4 5 6 7 8 9 10 11 |
// クリック:登録 // 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
1 2 3 4 5 6 7 8 9 10 11 12 |
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
1 2 3 4 5 6 7 8 9 10 11 12 |
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
1 2 3 4 5 6 7 8 9 |
// 描画 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// 描画 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
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// 描画 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リストに行を追加できるようになりました。
ここまでの ソースコード です。
次回は編集ボタンと新規ボタンの動作を実装して、この一連の記事を締め括りたいと思います。