こちらの記事は以下の書籍を参考にアウトプットとして執筆しました
React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで
TODOアプリに必要なコンポーネント
コンポーネント | 説明 |
---|---|
App | 各コンポーネントのまとめ役。データ管理 |
TodoInput | 入力フォームと登録ボタン |
TdoItem | 1つのTodo。タイトルと削除ボタンをもつ |
TodoList | Todoの一覧 |
Appコンポーネント
import React,{Component} from 'react'
これはどういう意味なのだろうか。
import X from Y
ならわかるが{}
が出てきて,
で区切られている
//デフォルトエクスポートはReactという名前で、
//また、Componentという名前付きエクスポートをインポートしている
import React,{Component} from 'react'
デフォルトエクスポートは1つのモジュールに1つ定義でき、
名前付きエクスポートは1つ以上定義できる。
import React,{Component} from 'react';
import TodoInput from './TodoInput';
import TodoList from './TodoList';
class App extends Component{
render(){
//TODO:後々stateで管理する
const tasks=[
{title:'Todo1つ目',id:0},
{title:'Todo2つ目',id:1},
];
return (
<div>
<h1>TODO App</h1>
<TodoInput/>
<TodoList tasks={tasks}/>
</div>
)
}
}
参考:React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで
このコードは'react'
からデフォルトエクスポートのReactと名前付きエクスポートのComponentをインポートし、
Componentを継承したAppクラスを定義している。
Appクラスの中身を見てみると
renderメソッド一つだけを定義している。
このメソッドはJSXを返す。
TodoInputコンポーネント
App.jsを見てみるとTodoinputコンポーネントのjsファイルはApp.jsと同じディレクトリに作成するようだ
import React, { Component } from 'react';
class TodoInput extends Component {
render() {
return (
<div>
<input placeholder="新規TODOを入力" />
<button>登録</button>
</div>
)
}
}
export default TodoInput;
参考:React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで
ここではTodoInputクラスを定義していて
renderメソッドを持っている
後はTodoInputをデフォルトエクスポートしている
TodoList
import React, { Component } from 'react';
import TodoItem from './TodoItem'
class TodoList extends Component {
render() {
//tasks内の各todoをTodoItemコンポーネントでエレメントにしている
//list変数はTodoItemエレメントの配列が入っている
const list = this.props.tasks.map(todo => {
return <TodoItem {...todo} key={todo.id} />
})
return (
<div>
<ul>
{list}
</ul>
</div>
)
}
}
export default TodoList;
参考:React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで
const list = this.props.tasks.map(todo => {
return <TodoItem {...todo} key={todo.id} />
})
App.jsでReactコンポーネントを
<TodoList tasks={tasks}/>
と定義してい箇所があるため、TodoList.jsでの
this.props.tasks
には
const tasks=[
{title:'Todo1つ目',id:0},
{title:'Todo2つ目',id:1},
];
が入る。
そしてこれをmap
で処理して新しいlist配列を生成している。
よって<TodoItem {...todo} key={todo.id} />
が展開されると以下のようになる
<TodoItem title='Todo1つ目' id=0 key=0 />
<TodoItem title='Todo2つ目' id=0 key=1 />
そしてTodoInHtemが入ったlist配列をrenderメソッドが返している。
TodoItem
import React from 'react'
function TodoItem(props) {
return (
<li>
{props.title}
</li>
)
}
export default TodoItem;
参考:React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで
state初期値
Appのtasksをstateで管理する。
初期値はconstructorで設定する
import React, { Component } from 'react';
import TodoInput from './TodoInput';
import TodoList from './TodoList';
class App extends Component {
constructor(props) {
super(props)
this.state = {
tasks: [
{
title: 'デフォルトTODO',
id: 0,
},
],
uniqueId: 1,
}
}
render() {
return (
<div>
<h1>TODO App</h1>
<TodoInput />
<TodoList tasks={this.state.tasks} />
</div>
)
}
}
stateは定義するためにconstructorで設定
以降変更するときはsetStateを使う
superでComponent側のconstructorでpropsを処理
addTodoメソッドの追加
新規TODOを追加できるようのメソッドを作成
addTodo(title) {
const { tasks, uniqueId, } = this.state;
tasks.push({
title, id: uniqueId
})
this.setState({
tasks, uniqueId: uniqueId + 1
})
}
参考:React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで
//これは分割をしている。
const { tasks, uniqueId, } = this.state;
//これは以下と同義
const tasks = this.state.tasks
const uniqueId = this.state.uniqueId
tasks.push({
title, id: uniqueId
})
これは省略されている。
title
はプロパティ名をtitle
として値を変数titleの値を設定している。
後はsetStateでstateに保存している。
このaddTodoをTodoInputで使うために渡す
<TodoInput addTodo={this.addTodo} />
最後にaddTodoメソッドで適切にstateを変更するために以下のコードを追記
constructor(props) {
//中略
this.addTodo=this.addTodo.bind(this)
}
bindはすべてのfunctionオブジェクトが持っているメソッド
addTodoメソッドでのthisはAppコンポーネントのつもりで書いているが、実際このメソッドを実行するのは別のDOM、コンポーネントであるため、stateを持たないものもある。
これを書くことでaddTodoのなかのthisは常にAppインスタンスを指し、this.stateはAppコンポーネントのstateを参照する。
bindを使わない方法として、アロー演算子を使うなどの手法があるが、コンポーネントを渡すときに毎回アロー関数を書く必要があるなど、手間が増えるため、当面はbindを使っていったほうがいい
イベントハンドリング
TodoInputにはpropsとしてaddTodoが渡されていた
<TodoInput addTodo={this.addTodo} />
クリックするたびにaddTodoメソッドを呼ぶメソッドを新たに追加
import React, { Component } from 'react';
class TodoInput extends Component {
constructor() {
super(props)
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
this.props.addTodo('新規TODO')
}
render() {
return (
<div>
<input placeholder="新規TODOを入力" />
<button onClic={this.handleClick}>登録</button>
</div>
)
}
}
export default TodoInput;
参考:React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで
またコンストラクタでbindしてhandleClickメソッドでのthisは常にTodoInputコンポーネントを指すことになった
button要素にonClick属性で関数を渡している。
これはブラウザのイベントと同じような感覚で引数も扱える。
from操作
Reactはフォーム入力もstateとして扱う。
フォーム入力はこのコンポーネントのみで利用するので(このコンポーネントってどこだよって読んでて思った)親コンポーネントのAppで定義する必要はない
次にstateとして持っている値をinput要素のvalueに設定
最後にユーザの入力ごとに実行され、その都度入力されている値をstateにセットするメソッドを書く