Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

: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: 参考

zenkigen
「テクノロジーを通じて、人と企業が全機現できる社会の創出に貢献する」 『全機現』という言葉は、「人の持つ能力の全てを発揮する」という禅の言葉です。 多くの大人が全機現し、それを見た子供達が、大人になることに希望を持つ社会を次世代に引き渡したい。 その思いが当社の創業精神です。
https://harutaka.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away