saga函数就是一些指令的集合,称为effects,副作用,用来描述任务
副作用 Side Effects 主要指的就是

  1. 异步网络请求
  2. 本地读取 localStorage/Cookie

reducers 纯函数

reducer有2个参数

  1. 第一个是,当前的 state状态
  2. 第二个是 ,payload 参数

reducers是唯一可以修改 state的,

  • reducer里面不能调用,其他 reducer
  • effect里面可以调用,其他 effect

effect里面通过,yield put(action),本质上就是 dispatch(action) 触发 state

  1. reducers: {
  2. save(state, payload) {
  3. return {
  4. ...state,
  5. ...payload,
  6. }
  7. }
  8. }

effects

effects,副作用对象,里面放的都是 generator函数

effect函数有 2个参数,

  1. 第一个参数是,action对象
  2. 第二个参数是,effects对象,可以结构出来

    1. call,用来调用一个方法
    2. put,用来派发一个新的 action,等价于 dispatch({type: ‘’, payload})
      1. put里面可以调用 另外一个 effects方法
    3. select,选择一个命名空间
    4. all,类似 Promise.all 调用多个方法

    5. ```jsx effects: {
    • init(action, effect) {

    } } ```

  • yield call 表示调用异步函数,
  • yield all([]) 调用多个异步函数
  • yield put 表示 dispatch(action)
  • yield select, 用来访问其它 model,获取当前 state的数据
  • take,
  • fork,
  • cancel

call 和 put 是saga的API,call负责调用 ajax
put 相当于dispatch,但是并不是真正执行dispatch,只是发送你指定的指令,交由saga中间件来执行这个指令

  1. // effect格式
  2. *func (action, effects) => void
  3. // async异步方法
  4. effects: {
  5. // *asyncAdd(action, effect) {
  6. *asyncAdd(action, {call, put, select}) {
  7. const { call, put } = effect
  8. yield call(lazy) // 等待一秒钟
  9. // effects里面 type不需要加 namespace
  10. yield put({ type: 'counter/add', payload: 100 })
  11. },
  12. }
  • 在Effects里,Generator函数通过yield命令将异步操作同步化,
  • 无论是yield 亦或是 async 目的只有一个: 让异步编写跟同步一样 ,从而能够很好的控制执行流程
  • *query(action, {call, put, select}){}表示一个worker Saga,监听所有的query action, 并触发一个ApI 调用以获取服务器数据

yield

saga使用了 Generator迭代器,解决异步回调地狱,做到了异步代码以同步书写

  1. // 延迟执行,ms
  2. const lazy = (time = 1000) =>
  3. new Promise(resolve => setTimeout(() => resolve(true), time))
  4. app.model({
  5. namespace: 'counter',
  6. state: { number: 0 },
  7. // 同步的方法
  8. reducers: {
  9. // state是之前的状态,return返回值是新状态 state
  10. add(state, action) {
  11. return { number: state.number + (action.payload || 10) }
  12. },
  13. },
  14. // async异步方法
  15. effects: {
  16. *asyncAdd(action, effect) {
  17. const { call, put } = effect
  18. yield call(lazy) // 等待一秒钟
  19. // effects里面 type不需要加 namespace
  20. yield put({ type: 'counter/add', payload: 100 })
  21. },
  22. }
  23. })

effect.jpg

监听 counter/asyncAdd,监听之后,执行 saga

  1. takeEvery('counter/asyncAdd', *asyncAdd(action, effects));

subscriptions 订阅数据源

Subscriptions 表示订阅,用于订阅一个数据源,然后按需 dispatch action

  • 格式为 ({ dispatch, history }) => unsubscribe
  • 比如:当用户进入 /y/monthCard/list 页面时,触发 action query 加载数据

    1. app.model({
    2. namespace: 'counter',
    3. state: { number: 0 },
    4. // 同步的方法
    5. reducers: {
    6. // state是之前的状态,return返回值是新状态 state
    7. add(state, action) {
    8. return { number: state.number + (action.payload || 10) }
    9. },
    10. },
    11. // async异步方法
    12. effects: {
    13. *asyncAdd(action, effect) {
    14. const { call, put } = effect
    15. yield call(lazy) // 等待一秒钟
    16. // effects里面 type不需要加 namespace
    17. yield put({ type: 'counter/add', payload: 100 })
    18. },
    19. },
    20. subscriptions: {
    21. setup({dispatch, history}){
    22. history.listen(({ pathname, query }) => {
    23. if(pathToRegexp(`/y/monthCard/list`).test(pathname)) {
    24. dispatch({ type: 'query' })
    25. }
    26. },
    27. },
    28. },
    29. })

    Subscriptions 表示订阅,用于订阅一个数据源,然后按需 dispatch action

select

在effects中对于param数据和当前的state数据进行再出处理,这里怎么获取state呢?采用select
select 获取到当前state中的数据

  1. {
  2. namespace: 'list',
  3. state: {user: 'lucy'},
  4. effects: {
  5. *asyncGetUserInfo({ payload }, { call, put, select }) {
  6. // select获取当前的 state
  7. const user = yield select(state => {
  8. console.log(state)
  9. return state.list.user
  10. });
  11. const res = yield call(getUserInfo, { ...payload, user });
  12. if (!res.data) return;
  13. yield put({ type: 'save', payload: res });
  14. },
  15. }
  16. }

多个 effect调用

https://blog.csdn.net/tianxintiandisheng/article/details/112475583