使用 redux-thunk、 redux-saga、 redux-observable、 MobX制作同样的一个 小项目:
这个项目调用github API查找 github 用户,点击头像之后还可以知道这个用户的 follower 和 following。简单来说,就是调用了三次 API(即三次异步请求)。
目录
本文不是教程,并不会手把手地教你如何使用他们,只是一个指引,一份示例,让你能够了解他们各自的特点,以便选择最适合自己的。
redux-thunk
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):
- 当 dispatch 一个 ACTION object 时,reducer 会更新数据
- 当 dispatch 一个函数时,我们就可以在里面做各种异步操作(利用 await),然后 dispatch 一个 ACTION object,之后 reducer 更新数据
redux-saga
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:
- 这个 ACTION object 没有被 sagas 监听,则 reducer 会更新数据
- 这个 ACTION object 被 sagas 监听,则走入 sagas 的流程,在 sagas 中 dispatch ACTION object,reducer 更新数据
redux-saga vs redux-thunk
-
原理不同:Sagas 不同于 Thunks,Thunks 是在 action 被创建时调用,而 Sagas 会在应用启动时调用(但初始启动的 Sagas 可能会动态调用其他 Sagas),是常驻后台的(因为 generator)。
-
redux-saga 有cancel、takeLeast这些操作,这是 async 做不到的(这也是 generator 相对 async 的优势)
-
redux-saga 易测试,比如它可以无阻塞地调用一个 generator(fork)、中断一个 generator (cancel)。这些特性在业务逻辑复杂的场景下非常适用。测试代码详见这里
-
redux-saga 保持了 action 的原义,保持 action 的简洁,把所有有副作用的地方独立开来(这样action里会很干净)。这种特性让 redux-saga 在业务逻辑简单的场景下,也能保持代码清晰简洁。
redux-observable
你要先了解 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
先看一个 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 纪要 也是可以的。
