Skip to content

Latest commit

 

History

History
317 lines (236 loc) · 19.8 KB

README_ja.md

File metadata and controls

317 lines (236 loc) · 19.8 KB

redux-saga

npm version CDNJS npm Discord Shield OpenCollective OpenCollective

redux-saga は React/Redux アプリケーションにおける副作用(データ通信などの非同期処理、ブラウザキャッシュへのアクセスのようなピュアではない処理)をより簡単で優れたものにするためのライブラリです。

Saga はアプリケーションの中で副作用を個別に実行する独立したスレッドのような動作イメージです。 redux-saga は Redux ミドルウェアとして実装されているため、スレッドはメインアプリケーションからのアクションに応じて起動、一時停止、中断が可能で、Redux アプリケーションのステート全体にアクセスでき、Redux アクションをディスパッチすることもできます。

ES6 の Generator 関数を使うことで読み書きしやすく、テストも容易な非同期フローを実現しています(もし馴染みがないようであればリンク集を参考にしてみてください)。それにより非同期フローが普通の同期的な JavaScript のコードのように見えます(async/await と似ていますが Generator 関数にしかないすごい機能があるんです)。

これまで redux-thunk を使ってデータ通信を行っているかもしれませんが、 redux-thunk とは異なりコールバック地獄に陥ることなく、非同期フローを簡単にテスト可能にし、アクションをピュアに保ちます。

はじめよう

インストール

$ npm install --save redux-saga

または、

$ yarn add redux-saga

別の方法として、UMD ビルドを HTML ページの <script> タグで直接使うこともできます。詳しくはこちら.

使い方

ボタンがクリックされたらリモートサーバから何らかのユーザデータを取得する UI を考えてみます(簡略化のため、起点となる部分のみ例示します)。

class UserComponent extends React.Component {
  ...
  onSomeButtonClicked() {
    const { userId, dispatch } = this.props
    dispatch({type: 'USER_FETCH_REQUESTED', payload: {userId}})
  }
  ...
}

コンポーネントはプレーンオブジェクトの Action を Store に送り出します。 USER_FETCH_REQUESTED Action を監視して、ユーザデータ取得の API 呼び出しを実行する Saga を作ります。

sagas.js

import { call, put, takeEvery, takeLatest } from 'redux-saga/effects'
import Api from '...'

// ワーカー Saga: USER_FETCH_REQUESTED Action によって起動する
function* fetchUser(action) {
  try {
    const user = yield call(Api.fetchUser, action.payload.userId)
    yield put({ type: 'USER_FETCH_SUCCEEDED', user: user })
  } catch (e) {
    yield put({ type: 'USER_FETCH_FAILED', message: e.message })
  }
}

/*
  USER_FETCH_REQUESTED Action が送出されるたびに fetchUser を起動します。
  ユーザ情報の並列取得にも対応しています。
*/
function* mySaga() {
  yield takeEvery('USER_FETCH_REQUESTED', fetchUser)
}

/*
  代わりに takeLatest を使うこともできます。

  しかし、ユーザ情報の並列取得には対応しません。
  もしレスポンス待ちの状態で USER_FETCH_REQUESTED を受け取った場合、
  待ち状態のリクエストはキャンセルされて最後の1つだけが実行されます。
*/
function* mySaga() {
  yield takeLatest('USER_FETCH_REQUESTED', fetchUser)
}

export default mySaga

定義した Saga を実行するには redux-saga ミドルウェアを使って Redux の Store と接続する必要があります。

main.js

import { createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'

import reducer from './reducers'
import mySaga from './sagas'

// Saga ミドルウェアを作成する
const sagaMiddleware = createSagaMiddleware()

// Store にマウントする
const store = createStore(reducer, applyMiddleware(sagaMiddleware))

// Saga を起動する
sagaMiddleware.run(mySaga)

// アプリケーションのレンダリング

ドキュメント

翻訳

ブラウザで umd ビルドを使用する

dist/ ディレクトリには redux-sagaumd ビルドもあります。 umd ビルドを使うときは window オブジェクトに ReduxSaga という名前で redux-saga が提供されます。 この方法を使用することで ES6 のimportシンタックスを用いずに Saga ミドルウェアを作成することができます。

var sagaMiddleware = ReduxSaga.default()

umd バージョンは webpack や browserify を使わない場合には便利です。unpkg から直接利用できます。

以下のビルドが利用可能です:

重要! ターゲットのブラウザが ES2015 の Generator をサポートしていない場合、babel のような有効な polyfill を提供しなければなりません。

polyfill は redux-saga の前にインポートされなければなりません。

import 'babel-polyfill'
// この後に
import sagaMiddleware from 'redux-saga'

サンプルをソースコードからビルドする

$ git clone https://github.com/redux-saga/redux-saga.git
$ cd redux-saga
$ yarn
$ npm test

以下は Redux リポジトリから移植したサンプルです。

カウンターのサンプル

3 つのカウンターのサンプルがあります。

counter-vanilla

ES2015 を使っていない素の JavaScript と UMD ビルドを使用したデモです。すべてのソースコードは index.html にインラインで埋め込まれています。

単純に index.html をブラウザで開くだけでサンプルを実行できます。

重要 ご利用のブラウザが Generator をサポートしている必要があります。 最新の Chrome / Firefox / MS Edge であれば大丈夫です。

counter

webpack と高レベル API takeEvery を使用したデモです。

$ npm run counter

# サンプルのテストを実行
$ npm run test-counter

cancellable-counter

低レベル API を使ったタスクのキャンセルのデモです。

$ npm run cancellable-counter

ショッピングカートのサンプル

$ npm run shop

# サンプルのテストを実行
$ npm run test-shop

非同期のサンプル

$ npm run async

# サンプルのテストを実行
$ npm run test-async

real-world サンプル(webpack による hot reloading 付き)

$ npm run real-world

# まだテストはありません・・・

TypeScript

TypeScript を Redux Saga で使用する場合にはDOM.IterableES2015.Iterableが必要になります。 targetES6であればすでに設定されている可能性がありますが、ES5の場合には手動で追加する必要があります。 tsconfig.jsonファイルと公式のコンパイラオプションドキュメントを確認してください。

ロゴ

様々な種類の Redux Saga 公式ロゴがロゴディレクトリにあります。

Redux Saga がasync/awaitでなく generators を採択した理由

Redux Saga がジェネレータの代わりにasync/await構文を使うように求めるいくつかの issueが提起されました。

私たちは今後もジェネレータを使用します。 async/awaitの主要なメカニズムは Promise であり、Promise ではスケジューリングの簡素さと既存の Saga のセマンティックを維持させることが難しいためです。 async/awaitではキャンセルといった特定の事項を許可しません。ですがジェネレータを使用すると作用をいつ、どのように実行するかを完全に制御できます。

支援者

毎月の寄付で私たちの開発を援助し、活動を継続できるように支援してください。 [支援者になる]

スポンサー

スポンサーとしてあなたのサイトへのリンクとなるロゴを Github 上の README に掲載しませんか。 [スポンサーになる]