redux-saga は、React において state の管理を redux にさせている場合に、非同期処理を担当する middleware。同様のアプリケーションに redux-thunk がある。
redux-thunk から redux-saga に乗り換え
https://hackernoon.com/moving-form-redux-thunk-to-redux-saga-5c19d0011ca0
まずは Generator がコア
function *generatorFunction (){} でgenerator を作る。
const it = generatorFunction () で it という イテレーターオブジェクトを作る。
it.next() で進める。 it.next().val で yield の値が取れる。
function *generatorFunction (){
yield 1;
yield 2;
yield 3;
}
console.log(it.next().value) //1
console.log(it.next().value) //2
console.log(it.next().value) //3
yield したものが return される。
for ( const value of generatorFunction ()){}
でとれる。
Generator, yield と async/await の類似性
async/await は、await によって promise オブジェクトが返されるまで待つ。これによって非同期処理を、書き方としては同期処理のように上から下へと書くことができる。
Generator における yield は、await と同じように、next() を待つ。これによって redux-saga は、処理を止めたり進めたりしている。
シンタックス
https://redux-saga.js.org/docs/introduction/BeginnerTutorial.html
saga.js を用意する。
import { delay } from 'redux-saga' // 時間差を作り出す
import { put, takeEvery, all } from 'redux-saga/effects'
// put はアクションのディスパッチを予約
// takeEvery は action を待ち受けるために使う
// all は saga をまとめて出力するために使う
// generator で定義。非同期処理を実行するもの
function* incrementAsync() {
yield delay(1000) //saga のdelay を使う。終わるまでここで待つ
yield put({ type: 'INCREMENT' }) // delayが終わればこの行に来る
// action をディスパッチする
}
// アクションを待ち受ける
function* watchIncrementAsync() {
yield takeEvery('INCREMENT_ASYNC', incrementAsync)
//受けたら関数を実行
}
// まとめておく
// notice how we now only export the rootSaga
// single entry point to start all Sagas at once
export default function* rootSaga() {
yield all([
helloSaga(),
watchIncrementAsync()
])
}
ミドルウェアの適応
import "babel-polyfill" // generator とかに必要っぽい import React from 'react' import ReactDOM from 'react-dom' import { createStore, applyMiddleware } from 'redux' import createSagaMiddleware from 'redux-saga' import rootSaga from './sagas' // saga関係がまとまっているもの import reducer from './reducers' const sagaMiddleware = createSagaMiddleware() //ミドルウェアを作る //redux にミドルウェアを噛ませる const store = createStore( reducer, applyMiddleware(sagaMiddleware) ) //サーガを起動 sagaMiddleware.run(rootSaga)
関数の実行と引数の渡し方
call を使って function を実行する。これはイテレーターか、もしくは promise を返す function を使う。例えば fetch など。promise が返されるまで、yield は待つ。
import { call, put } from 'redux-saga/effects'
// call が非同期処理をする関数を呼び出すために必要
export function* fetchData(action) {
try {
// Api.fetchUser ha promise を返すものとする
// call(function,arg) ここでは action を引数として渡した
// promise の返り値が const data に入る
const data = yield call(Api.fetchUser, action.payload.url)
// アクションをディスパッチ
yield put({type: "FETCH_SUCCEEDED", data})
} catch (error) {
yield put({type: "FETCH_FAILED", error})
}
}
sandbox