riskers / blog

:pencil2: 博客写在 Issues 里
http://riskers.github.io/
MIT License
1.13k stars 96 forks source link

Redux、MobX 数据流的总结 #32

Open riskers opened 6 years ago

riskers commented 6 years ago


使用 redux-thunkredux-sagaredux-observableMobX制作同样的一个小项目:

data flow demo

这个项目调用github API查找 github 用户,点击头像之后还可以知道这个用户的 follower 和 following。简单来说,就是调用了三次 API(即三次异步请求)。


目录

本文不是教程,并不会手把手地教你如何使用他们,只是一个指引,一份示例,让你能够了解他们各自的特点,以便选择最适合自己的。


redux-thunk

code

redux-thunk我们在 Redux 中操作异步最简单的方法。配合 async/await,你可以像写同步代码一样进行异步操作。

示例

// action creators
const getUsers = username => {
  async dispatch => {
    dispatch({
      type: 'LOADING'
    })

    try{
      const response = await fetch(`https://example.com/`)
      let data = await response.json()

      dispatch({
        type: 'SUCCESS',
        payload: data
      })
    }catch(error) {
      dispatch({
        type: 'FAILURE',
        error: error
      })
    }
  }
}

redux-thunk flow

      dispatch                                       dispatch           update
VIEW ----------> function ----------> ACTION object ---------> REDUCER --------> STORE --------> STATE
|          (return async dispatch)                                ^
|                                                                 |
|                                                                 |
|                                                                 |
|       dispatch                                                  |
|---------------------> ACTION object -----------------------------

VIEW 会 dispatch 一个 ACTION object 或一个高阶函数(返回 async function):


redux-saga

code

redux-saga 简化了 action creator,redux-saga 通过创建 Sagas 将所有的异步操作逻辑收集在一个地方集中处理。Sagas 可以被看作是在后台运行的进程,监听发起的 action,然后决定基于这个 action 来做什么:是发起一个异步调用(比如一个 Ajax 请求),还是发起其他的 action 到 Store,甚至是调用其他的 Sagas。一旦出发 sagas 监听的 action,sagas 会通过一系列的effects dispatch (比如 put)一个 action。

示例

// action.js
export const searchUsers = (username, page) => {
  return {
    type: CONST.FETCH_GITHUB_SEARCH_USER,
    payload: {
      username,
      page
    }
  }
}
// App/sagas.js
function* fetchUsers(action) {
  let {
    username,
    page
  } = action.payload

  yield put({
    type: CONST.FETCH_GITHUB_SEARCH_USER_LOADING
  })

  yield call(delay, 2000)

  try {
    let response = yield call(fetch, `https://api.github.com/search/users?q=${username}&page=${page}`)
    let data = yield response.json()

    yield put({
      type: CONST.FETCH_GITHUB_SEARCH_USER_SUCCESS,
      payload: data
    })
  }catch(e) {
    yield put({
      type: CONST.FETCH_GITHUB_SEARCH_USER_FAILURE,
      error: "No This User"
    })
  }
}

export default function* () {
  yield takeLatest(CONST.FETCH_GITHUB_SEARCH_USER, fetchUsers)
}
// sagas/index.js
import AppSaga from 'containers/App/sagas'

export default function* rootSaga() {
  yield AppSaga()
}

redux-saga flow

      dispatch                  not match            update          update
VIEW ----------> ACTION object -----------> REDUCER --------> STORE --------> STATE
                       |                       ^
                       |                       |
                       |  match                |
                       |                       |
                       |  (data)               |
                       |                       |
                      \|     dispatch          |
                     SAGAS ------------>  ACTION object

VIEW dispatch 一个 ACTION object:

redux-saga vs redux-thunk


redux-observable

code

你要先了解 rxjs ,然后再往下读。因为 redux-observable 就是让你能够在 Redux 中使用 rxjs。

为了方便理解 rxjs,我做了一个纯 js 版的项目 jsbin,之后能够我们再把它改成 react 版的。

redux-observable flow

      dispatch                  not match            update          update
VIEW ----------> ACTION object -----------> REDUCER --------> STORE --------> STATE
                       |                       ^
                       |                       |
                       |  match                |
                       |                       |
                       |  (data)               |
                       |                       |
                      \|     dispatch          |
                     EPICS ------------>  ACTION object

Epic 是 redux-observable 的核心,它是一个函数,接收 actions 流作为参数并且返回 actions 流: Actions 入, actions 出。返回的 actions 会通过 store.dispatch() 立刻被分发,所以 redux-observable 实际上会做 epic(action$, store).subscribe(store.dispatch)

redux-observable vs redux-saga

可以看到,redux-observable 和 redux-saga 的数据流是相似的。关于他们的异同,可以查看这两篇文章,不再赘述:


mobx

code

先看一个 demo,它包含了 @action @observable @observer @computed @inject 等重要概念。

MobX flow

                            modify                    update                    trigger
Events ----->  Actions  ------------->     State     --------> Computed values ---------->  Reactions
              (@action)                (@observable)             (@computed)               (@observer)
                 ^                                                                              |
                 |                                                                              |
                 |                                 (mobx-react)                                 |
                 |------------------------------------------------------------------------------|

MobX vs Redux

MobX vs Redux: Comparing the Opposing Paradigms 演讲已经介绍,不能看视频的看 MobX vs Redux: Comparing the Opposing Paradigms - React Conf 2017 纪要 也是可以的。



向我捐助 | 关于我 | 工作机会