ReduxSagaの紹介

Redux Sagaは、Reduxの副作用を処理するために使用されるライブラリです。アクションを起動すると、アプリの状態が変化し、この状態の変化から派生した何かを行う必要がある場合があります

ReduxSagaをいつ使用するか

を使用するアプリケーションで戻ってきた、アクションを実行すると、アプリの状態が変化します。

これが発生すると、この状態の変化から派生する何かを行う必要がある場合があります。

たとえば、次のようにします。

  • サーバーにHTTP呼び出しを行う
  • WebSocketイベントを送信する
  • からいくつかのデータをフェッチしますGraphQLサーバ
  • キャッシュまたはブラウザのローカルストレージに何かを保存する

…あなたはその考えを理解しました。

これらはすべて、アプリの状態とは実際には関係がないか、非同期であるため、アクションやレデューサーとは異なる場所に移動する必要があります(技術的にはたぶん......だろう、クリーンなコードベースを持つのは良い方法ではありません)。

副作用を解決するReduxミドルウェアであるReduxSagaをご利用ください。

ReduxSagaの基本的な使用例

実際のコードを示す前に理論に飛び込むのを避けるために、サンプルアプリを作成するときに直面した問題をどのように解決したかを簡単に説明します。

チャットルームでは、ユーザーがメッセージを書くとすぐに画面にメッセージを表示して、迅速なフィードバックを提供します。これは、Reduxアクション

const addMessage = (message, author) => ({
  type: 'ADD_MESSAGE',
  message,
  author
})

状態はレデューサーを介して変更されます。

const messages = (state = [], action) => {
  switch (action.type) {
    case 'ADD_MESSAGE':
      return state.concat([{
        message: action.message,
        author: action.author
      }])
    default:
      return state
  }
}

Redux Sagaを初期化するには、最初にインポートしてから、佐賀Reduxストアへのミドルウェアとして:

//...
import createSagaMiddleware from 'redux-saga'
//...

次に、ミドルウェアを作成し、新しく作成したReduxストアに適用します。

const sagaMiddleware = createSagaMiddleware()

const store = createStore( reducers, applyMiddleware(sagaMiddleware) )

最後のステップは、サガを実行することです。それをインポートして、ミドルウェアのrunメソッドに渡します。

import handleNewMessage from './sagas'
//...
sagaMiddleware.run(handleNewMessage)

私たちはただ物語を書く必要があります./sagas/index.js

import { takeEvery } from 'redux-saga/effects'

const handleNewMessage = function* handleNewMessage(params) { const socket = new WebSocket(‘ws://localhost:8989’) yield takeEvery(‘ADD_MESSAGE’, (action) => { socket.send(JSON.stringify(action)) }) }

export default handleNewMessage

このコードの意味は次のとおりです。毎回インクルードADD_MESSAGEアクションが発生し、メッセージを送信しますWebSocketこの場合に応答するサーバーlocalhost:8989

の使用に注意してくださいfunction*、これは通常の機能ではありませんが、発生器

舞台裏でどのように機能するか

であること戻ってきたミドルウェアであるReduxSagaは、Reduxアクションをインターセプトし、独自の機能を注入できます。

把握する必要のあるいくつかの概念があります。ここに、頭に入れておきたい主なキーワードをまとめます。佐賀発生器ミドルウェア約束する一時停止履歴書効果ディスパッチアクション満たされた解決しました産出降伏

A佐賀に反応するいくつかの「物語」です効果あなたのコードが引き起こしていること。これには、HTTPリクエストやキャッシュに保存するプロシージャなど、前に説明したものの1つが含まれている可能性があります。

作成しますミドルウェアのリストでサガ実行するには、1つ以上にすることができ、このミドルウェアをReduxストアに接続します。

A佐賀発生器関数。いつ約束する実行され、降伏、ミドルウェア中断しますインクルード佐賀まで約束するです解決しました

一度約束するです解決しましたミドルウェア履歴書佐賀、次まで産出ステートメントが見つかり、そこにあります一時停止再びそのまで約束する 解決します

佐賀コード内で、生成します効果によって提供されるいくつかの特別なヘルパー関数を使用するredux-sagaパッケージ。まず、次のリストを作成できます。

  • takeEvery()
  • takeLatest()
  • take()
  • call()
  • put()

いつ効果実行されると、佐賀です一時停止まで効果です満たされた

例えば:

import { takeEvery } from 'redux-saga/effects'

const handleNewMessage = function* handleNewMessage(params) { const socket = new WebSocket(‘ws://localhost:8989’) yield takeEvery(‘ADD_MESSAGE’, (action) => { socket.send(JSON.stringify(action)) }) }

export default handleNewMessage

いつミドルウェアを実行しますhandleNewMessage佐賀、それ止まるyield takeEvery指導と待つ((非同期的に、もちろん)までADD_MESSAGEアクションは派遣。次に、コールバックを実行し、佐賀できる履歴書

基本的なヘルパー

ヘルパーは、低レベルのsagaAPIの上位にある抽象化です。

エフェクトを実行するために使用できる最も基本的なヘルパーを紹介しましょう。

  • takeEvery()
  • takeLatest()
  • take()
  • put()
  • call()

takeEvery()

takeEvery()、いくつかの例で使用されているのは、それらのヘルパーの1つです。

コード内:

import { takeEvery } from 'redux-saga/effects'

function* watchMessages() { yield takeEvery(‘ADD_MESSAGE’, postMessageToServer) }

ザ・watchMessagesジェネレータは、ADD_MESSAGEアクションが発火し、毎回それは発砲します、それは呼び出すつもりですpostMessageToServer機能、無限に、そして同時に(必要はありませんpostMessageToServer新しいonceが実行される前に実行を終了する)

takeLatest()

もう1つの人気のあるヘルパーはtakeLatest()、これは非常によく似ていますtakeEvery()ただし、同時実行を回避するために、一度に1つの関数ハンドラーのみを実行できます。ハンドラーがまだ実行されているときに別のアクションが実行されると、ハンドラーはそれをキャンセルし、利用可能な最新のデータを使用して再実行します。

と同じようにtakeEvery()、ジェネレーターは停止せず、指定されたアクションが発生したときにエフェクトを実行し続けます。

take()

take()は、1回だけ待機するという点で異なります。待機中のアクションが発生すると、Promiseが解決され、イテレータが再開されるため、次の命令セットに進むことができます。

put()

Reduxストアにアクションをディスパッチします。 ReduxストアまたはディスパッチアクションをSagaに渡す代わりに、次を使用できます。put()

yield put({ type: 'INCREMENT' })
yield put({ type: "USER_FETCH_SUCCEEDED", data: data })

これは、テストで簡単に検査できるプレーンオブジェクトを返します(テストについては後で詳しく説明します)。

call()

佐賀で関数を呼び出したい場合は、promiseを返す生成されたプレーン関数呼び出しを使用して呼び出すことができます。

delay(1000)

しかし、これはテストではうまく機能しません。代わりに、call()その関数呼び出しをラップして、簡単に検査できるオブジェクトを返すことができます。

call(delay, 1000)

戻り値

{ CALL: {fn: delay, args: [1000]}}

エフェクトを並行して実行する

エフェクトを並行して実行するには、all()そしてrace()、それらが行うことは非常に異なります。

all()

あなたが書くなら

import { call } from 'redux-saga/effects'

const todos = yield call(fetch, ‘/api/todos’) const user = yield call(fetch, ‘/api/user’)

二番目fetch()最初の呼び出しが成功するまで、呼び出しは実行されません。

それらを並行して実行するには、それらをにラップしますall()

import { all, call } from 'redux-saga/effects'

const [todos, user] = yield all([ call(fetch, ‘/api/todos’), call(fetch, ‘/api/user’) ])

all()両方が解決されるまで解決されませんcall()戻ります。

race()

race()とは異なりall()すべてのヘルパーの呼び出しが戻るのを待たないことによって。戻るのを待つだけで完了です。

どちらが先に終了するかを競うレースですが、その後は他の参加者のことを忘れてしまいます。

これは通常、何かが発生するまで永久に実行されるバックグラウンドタスクをキャンセルするために使用されます。

import { race, call, take } from 'redux-saga/effects'

function* someBackgroundTask() { while(1) { //… } }

yield race([ bgTask: call(someBackgroundTask), cancel: take(‘CANCEL_TASK’) ])

いつCANCEL_TASKアクションが発行されると、他の方法では永久に実行される他のタスクを停止します。

私の無料ダウンロードReactハンドブック


その他の反応チュートリアル: