# 関連
- Reactの環境構築を最短で行う
- 【React】ToDoアプリを作ってみよう【前編】
- 【React】ToDoアプリを作ってみよう【後編】
- 【React】ToDoアプリを発展させよう【非同期処理】←ここ
# 目標
- Reactで作ったToDoアプリに機能を付け足していきます。
- 今回は起動時に非同期処理でTodoをsetするようにします。
- 見本:GitHub
# 手順
## データ取得先を用意する
### data.json
public/data.json
[
{
"title": "Hello, React!",
"desc": "Reactはじめました"
},
{
"title": "Hello, Redux!",
"desc": "Reduxもはじめました"
}
]
- publicディレクトリにデータの入ったjsonファイルを作成します。ここからデータを取得することで、模擬的に非同期処理を実装します。
- titleとdesc以外は決まった値なので、App.jsでsetするようにしましょう。
### App.js
src/App.js
...
constructor() {
super()
const todos = []
this.state = {
isLoading: false,
hasError: false,
todos: todos,
countTodo: todos.length + 1,
}
}
...
- constructorのTodoの中身を消去しておきます。
- これから使うisLoadingとhasErrorをstateに追加します。
## 非同期処理の実装
### App.js
src/App.js
...
fetchData(url) {
this.setState({ isLoading: true })
fetch(url)
.then((response) => {
console.log(response)
if (!response.ok) {
throw Error(response.statusText);
}
this.setState({ isLoading: false })
return response
})
.then((response) => response.json())
.then((data) => {
let countTodo = this.state.countTodo
const todos = data.map(data => {
const todo = Object.assign({}, data, { id: countTodo++, done: false })
return todo
})
this.setState({ todos, countTodo })
})
.catch(() => this.setState({ hasError: true }))
}
...
- 関数**fetchData()**を定義し、非同期処理の中身を記述します。まず、
isLoading: true
というstateをsetし、データロード中であることを定めます。 - fetch()メソッドの**.then()**を使うことで段階を踏んで処理ができます。
- 1つ目の.thenではresponseのokプロパティでアクセスの判定をします。trueの場合は正常にアクセスできているので、
isLoading
をfalseにします。 - 2つ目の.thenでは.json()メソッドでresponseがjsonであることを定義します。一行のアロー関数なので自動的にreturnされています。
- 3つ目の.thenでは渡されたjsonデータをもとにtodoを組み立てています。**Object.assign()**は第1引数を
{}
とすることで、第2引数以降をmerge(結合)した新しいObjectを生成します。 - どこかで処理がうまくいかなかった時、 catch()が呼ばれるため、
hasError: true
というstateをsetします。
### App.js
src/App.js
...
<TodoList
todos={this.state.todos}
setTodoStatus={this.setTodoStatus.bind(this)}
isLoading={this.state.isLoading}
hasError={this.state.hasError}
/>
...
- TodoListコンポーネントにisLoadingとhasErrorのStateを渡すのを忘れないように。
### TodoList.js
TodoList.js
...
render() {
if (this.props.isLoading) {
return <h2>loading . . . </h2>;
}
if (this.props.hasError) {
return <h2>error</h2>;
}
...
- renderの中にisLoadingかhassErrorがtrueだった時の処理を追記します。
## 非同期処理を起動時に呼び出す
### App.js
src/App.js
...
componentDidMount() {
this.fetchData('data.json');
}
...
- 最後にfetchData()を起動時に呼び出すようにします。**componentDidMount()**はcomponentがDOMに追加された後で自動的に呼ばれるため、これを利用しましょう。
- この中で先ほど定義したfetchData()を呼び出し、引数に
data.json
を渡します。 - これで、起動時に一瞬「Loading...」が表示されてTodoが表示されます。jsonの書き方がおかしかったりすると「Error」が表示されます。
- 内容に不備等ありましたら、お手数ですがコメントにてお願いします。
# 参考