Shoeisha Technology Media

CodeZine(コードジン)

記事種別から探す

Reduxで非同期処理を行う~Middlewareを使って実装する方法

基礎からはじめるReact入門 第9回

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2018/06/15 14:00

 第8回ではFluxの概念を紹介しながらReduxの基本的な使い方を学びましたが、Reduxを実際の業務で使う場合には、実践的なノウハウが必要になります。今回は、よりReduxを現場で使えるツールとして活用するために、Middlewareの仕組みを導入しながら、外部との通信を行う際に必須となる非同期処理を行う方法について学ぶことを目的とします。

目次

対象読者

  • JavaScriptとWeb開発の基礎に理解がある方
  • Reactに興味/関心があり、これから学び始める方

前提環境

 筆者の検証環境は以下の通りです。

  • macOS High Sierra 10.13.3
  • Node.js v8.9.4/npm 5.6.0
  • React 16.3.1
  • redux 3.7.2
  • react-redux 5.0.7
  • redux-thunk 2.2.0

非同期処理とRedux

 本格的なGUIアプリケーションを開発する上で、避けては通れないのが非同期処理です。非同期処理はネットワークやデータベースなどの時間がかかる処理を扱う場合によく用いられる手法で、GUIアプリケーションが外の世界にアクセスしようとする場合には、ほぼ必須となる概念です。

非同期処理についておさらい

 まずは、非同期処理について簡単におさらいしておきましょう。「非」同期的な処理であると言うからには、同期的な処理もあるということなので、まずは同期的な処理について確認します。同期的な処理とは、上から下に向かってスコープ内の式をひとつひとつ順番に実行し、前の式が終わってから次の式を実行するという、至って普通の実行方式です(図1)。同期的な処理によって書かれた関数は、returnによって値を返すことができます。

図1:同期的な処理
図1:同期的な処理

 これに対して、非同期的な処理は、スコープ内に書かれたすべての処理がひと続きに実行されるわけではありません。この説明ではややこしいので、図で表します。図2に示したasyncFunction関数は、そのスコープ内にdoAwesome関数の呼び出しを含んでいます。doAwesome関数にはコールバック関数が渡されており、引数cを使った処理がコールバック関数の中で行われています。

図2:非同期的な処理の外側のスコープの動き
図2:非同期的な処理の外側でのスコープの動き

 asyncFunction関数は、まず同期的に実行できる式を実行していきます。図2の例では、①と②の部分が同期的に実行できる処理です。この時点で行われるのは、「コールバック関数のオブジェクトを生成してdoAwesomeの第3引数として渡す」処理までで、コールバック関数自体は実行されません。

 では、コールバック関数はいつ実行されるのかというと、これはdoAwesomeの内部で呼び出されたときなので、いつになるのかは分かりません。50ミリ秒後なのか3秒後なのかは分かりませんが、おもむろにコールバック関数が実行されます(図3)。

図3:非同期的な処理の内側のスコープの動き
図3:非同期的な処理の内側でのスコープの動き

 ③のように同期的な処理とは別のタイミングでの呼び出し方を「非同期的な呼び出し」と呼ぶことがあります。つまり、コールバック関数の実装はいつ呼ばれても問題ないように作っておくことが求められます。また、こういった作りになっている都合上、コールバック関数内に実装された処理の結果をasyncFunction関数の結果として返すことはできません。

 同期的な処理に比べると考慮すべきことが増えてしまいますが、UIのイベント処理のような「早めに終わらせないと画面が止まってしまう」といった処理においてはとても有用な考え方なので、ぜひ活用するべきでしょう。幸いなことに、JavaScriptの文化圏では時間のかかる処理をPromiseによって非同期化することが多くの分野で標準化されています。リスト1は通信を行うためのグローバル関数であるfetchを使った場合の例です。

[リスト1]fetchとPromiseによる非同期処理の例
fetch("https://example.com/api/hoge") // Promiseオブジェクトが返却される
.then(response => {
  // 通信が成功した場合の処理
})
.catch(error => {
  // エラーが発生した場合の処理
})

 時間のかかる処理を書く場合には、非同期処理にすることを強制されるので、通信などの関数を覚えていく中で、自然と非同期処理が身についていくことでしょう。

Reduxの非同期処理はどこで行うのか

 Reduxに非同期処理を組み込んでいく上で、まず確認しておかなければならないのは、Reducerの特性です。前回紹介した通り、Reducerは既存の状態とActionを受け取り、新しいデータを生み出して返却する関数群でした。データを返却する必要があるということは、Reducerの関数内で非同期処理を行ったとしても、その結果を返却することができません。Reducerの中に非同期処理を記述しても、意味が無いのです。

図4:Reduxの中で非同期処理を行うタイミング
図4:Reduxの中で非同期処理を行うタイミング

 Reducerの処理によって生み出された新しい状態はそのままViewの更新に使われるため、Reducer以降に非同期処理を行える場所はありません。Reducerが実行されるより前の段階のどこか、ということになります。では、どこで非同期処理を行うのが適切なのかというと、デファクトスタンダードな方法は存在していません。大まかには次の2つのうちどちらかの方法を採用することになります。

  • Middlewareを使う方法
  • Middlewareを使わない方法

 Middlewareを使った場合は、「dispatch関数を実行した後で、Reducerが実行される前」のタイミングで非同期処理を行います。一方で、Middlewareを使わない場合は、「非同期処理が終わってからdispatch関数を初めて呼ぶ」といった順序になります。本記事では、前者の例としてredux-thunkというMiddlewareの使い方を紹介します。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • WINGSプロジェクト 中川幸哉(ナカガワユキヤ)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2017年5月時点での登録メンバは52名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂き...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XMLD...

バックナンバー

連載:基礎からはじめるReact入門

もっと読む

All contents copyright © 2005-2018 Shoeisha Co., Ltd. All rights reserved. ver.1.5