17
23

More than 5 years have passed since last update.

【React】ToDoアプリを発展させよう【非同期処理】

Last updated at Posted at 2017-07-19

:star: 関連

:star: 目標

  • Reactで作ったToDoアプリに機能を付け足していきます。
  • 今回は起動時に非同期処理でTodoをsetするようにします。
  • 見本:GitHub

todo-app4.gif

:star: 手順

:pencil: データ取得先を用意する

:pencil2: data.json

public/data.json
[
  {
    "title": "Hello, React!",
    "desc": "Reactはじめました"
  },
  {
    "title": "Hello, Redux!",
    "desc": "Reduxもはじめました"
  }
]

  • publicディレクトリにデータの入ったjsonファイルを作成します。ここからデータを取得することで、模擬的に非同期処理を実装します。
  • titleとdesc以外は決まった値なので、App.jsでsetするようにしましょう。

:pencil2: 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に追加します。

:pencil: 非同期処理の実装

:pencil2: 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します。

:pencil2: 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を渡すのを忘れないように。

:pencil2: 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だった時の処理を追記します。

:pencil: 非同期処理を起動時に呼び出す

:pencil2: App.js

src/App.js
...

  componentDidMount() {
    this.fetchData('data.json');
  }

...
  • 最後にfetchData()を起動時に呼び出すようにします。componentDidMount()はcomponentがDOMに追加された後で自動的に呼ばれるため、これを利用しましょう。
  • この中で先ほど定義したfetchData()を呼び出し、引数にdata.jsonを渡します。
  • これで、起動時に一瞬「Loading...」が表示されてTodoが表示されます。jsonの書き方がおかしかったりすると「Error」が表示されます。

:star2: 以上で非同期処理は完成です!

todo-app9.gif

  • 内容に不備等ありましたら、お手数ですがコメントにてお願いします。

:star: 参考

17
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
23