redux-saga is a middleware that manages asynchronous operation of Redux application. Its function is similar to redux-thunk + async/await. It stores all the asynchronous operation logic in one place through Sagas creation. Effects in effects

redux-saga of

redux-saga is a plain text JavaScript object, containing some instructions that will be executed by saga JavaScript. The execution of these instructions include the following three types:

  1. launched an asynchronous call (such as a Ajax request)
  2. initiated other action to update contains Store

Effects Sagas

calls the other instructions in many specific asynchronous API reference check


the characteristics of convenient testing, for example:

 assert.deepEqual ( (.Value), call (Api.fetch,'/products') 


  1. action can maintain its purity, the asynchronous operation focused on saga for processing
  2. (

  3. watch/worker monitor -> Executive) the work in the form of
  4. is implemented as generator
  5. < li> The application scenario with complex asynchronous logic is supported well,

  6. realizes the asynchronous logic finely and finely, so that the process is clearer and clearer. Bug is easy to track and solve.
  7. in a synchronous way of writing asynchronous logic, more in line with people's thinking logic
  8. if there is a scene from redux-thunk to redux-saga

: if the user needs to authenticate the user logs in, when username and password meet the requirements.

> "to get the user data (user.js):

 user.js import request from / /'axios'/ / define / / define; constants initial state export default reducer export const / / loadUserData = (uid) => (dispatch); async => try dispatch ({{{type: USERDATA_REQUEST {data}}); let = await request.get (`/users/${uid}`); dispatch (type: {USERDATA_SUCCESS, data}); catch (error) {dispatch} ({type: USERDATA_ERROR}}}, error); 

authentication login logic (login.js):

 import request from'axios'; import {loadUserData} from'./user'; export const = login (user, pass) => async (dispatch) {try {=> Dispatch ({type:} LOGIN_REQUEST {data}); let = await ('/login', {user, pass}); await dispatch (loadUserData (data.uid); dispatch (type:) {LOGIN_SUCCESS, data}); catch (error) {dispatch} ({type:}}; LOGIN_ERROR, error)}


asynchronous logic can all write into saga.js:

 export function* (loginSaga) while (true) {{const} = {user, pass yield take (LOGIN_REQUEST) / / wait for the Store specified on the action LOGIN_REQUEST try {let {data} {call = yield (loginRequest, user, pass}); / / block, request background data yield fork (loadUserData, data.uid); / / loadUserData yield put (non blocking execution {type: LOGIN_SUCCESS,  data }); //发起一个action,类似于dispatch   } catch(error) {    yield put({ type: LOGIN_ERROR, error });   }   } }  export function* loadUserData(uid) {  try {   yield put({ type: USERDATA_REQUEST });   let { data } = yield call(userRequest, `/users/${uid}`);   yield put({ type: USERDATA_SUCCESS, data });  } catch(error) {   yield put({ type: USERDATA_ERROR, error });  } }  


对于 redux-saga, 还是有很多比较难以理解和晦涩的地方,下面笔者针对自己觉得比较容易混淆的概念进行整理:

take 的使用

take 和 takeEvery 都是监听某个 action, 但是两者的作用却不一致,ta The keEvery responds to every time the action triggers, and the take is the response when the execution flow is executed to the take statement. TakeEvery is listening on action, and perform processing functions corresponding to action, when to perform and how to respond to action and not much control, the called task cannot control when invoked, and they cannot control when to stop listening, it can only be matched with each action again and again called. But take can decide when to respond to a action and follow up after the response in the generator function. For example, the operation of logger in
to monitor all types of action trigger, use takeEvery to achieve the following:

 import from'redux-saga'function* {takeEvery} watchAndLog {yield* (getState) takeEvery (function* *, logger (action) {//do some logger operation / / in the callback function in 

take}}) used to achieve the following:

 import from'redux-saga/effects' function* watchAndLog {take} {(getState) while (true) {const action = yield take //do some logger operation ('*')})} / / take and parallel 

while (true) which means once arrived in the process the last step (logger), initiated by waiting for a new any action a new iteration (logger process).

blocking and non blocking

call operation is used to initiate asynchronous operation. For generator, call is blocking operation. It can not execute or handle anything else before the end of Generator call. However, fork is a non blocking operation. When fork transfers tasks, the task will be executed in the background. At this time, the execution flow can continue to execute behind, rather than wait for the result to return.

as follows:

 function* loginFlow login scenario ((true)) {while {const {user password} = yield take const token yield ('LOGIN_REQUEST') = call (authorize, user, password) if (token) {yield call (Api.storeItem ({token}) yield ('LOGOUT') take yield call (Api.clearItem) ('token')}})} 

call in authorize to ask if, the results did not return, but this time the user triggered LOGOUT action, the LOGOUT will be ignored and not be treated, because loginFlow is blocked in authorize, did not perform to take ('LOGOUT')

executed at the same time there

in case of multiple tasks at the same time a scene needs to perform multiple tasks, such as request users data and products data, should Use the following way:

 import {call} / / from'redux-saga/effects'const [users products] synchronous execution, yield = [call (fetch,'/users'), call (fetch,'/products')] / / / / const users instead of sequential execution (fetch, call = yield, products = yield / users') call (fetch,'/products') 

when the yield is behind an array, then the array operation will be in accordance with the implementation of Promise.all rules to perform, genertor will know all the effects obstruction were performed

complete source code interpretation in each use of redux-saga project, there will be a sagas as follows the middleware is added to the Store logic are the main file:

 const ({sagaMoni sagaMiddleware = createSagaMiddleware Tor} store = createStore (const) reducer, applyMiddleware (sagaMiddleware)) (rootSaga) 

createSagaMiddleware is the method of deriving redux-saga core source code in the src/middleware.js file:

 export default function sagaMiddlewareFactory (context = {options} {} {},... = function (sagaMiddleware) {...} {{getState, dispatch) const channel = stdChannel (channel.put) = (options.emitter || identity) (channel.put) = runSaga.bind (null, channel, dispatch {context, getState, sagaMonitor, logger, onError, effectMiddlewares, return next => action}); => {if (sagaMonitor; & & sagaMonitor.actionDispatched) {sagaMonitor.actionDisp Atched (action)} const result = next (action) / / hit reducers channel.put (action) return result 

}}}... This logic is executed (sagaMiddleware), the function which assigns runSaga to and the execution, finally returned to the middleware. Then look at the runSaga (

 export) logic: function runSaga (options, Saga,... Args) {... Const task = proc (iterator, channel, wrapSagaDispatch (dispatch), getState, context, logger, onError {sagaMonitor, middleware}, effectId,, if (sagaMonitor) {sagaMonitor.effectResolved (effectId) task, return task}

)} This function is defined to return a task object, the task is produced by proc proc.js:

 export default function, from iterator, stdChannel, proc (dispatch = NOOP, getState = NOOP, parentContext = options = {} {}, parentEffectId = 0, name ='anonymous'. Cont, const) {... Task = newTask (parentEffectId, name, iterator, cont) {n mainTask = const Ame, cancel: cancelMain, isRunning: true const taskQueue} = forkQueue (name, mainTask, end) next (return) task... Function next (Arg, isErr) {... If (! Result.done) {digestEffect (result.value, parentEffectId, next ',}

}})... Where digestEffect implementation of the effectTriggerd () and (runEffect), is the implementation of effect, including runEffect (effect) defined in different execution of functions, each function of effect are realized in proc.js. In addition to some core methods,

also provides a series of helper files. The function of these files is to return a class iterator object, which is convenient for subsequent traversal and execution. Here is no specific analysis. Redux-saga

is the whole content of this article, I hope to help you, and hope that you can support a lot of scripting home.

This paper fixed link: | Script Home | +Copy Link

Article reprint please specify:The first and the use of redux-saga | Script Home

You may also be interested in these articles!