状态管理
写这篇笔记更正之前理解的误区,背景呢,一次需求中实现根据参数 itemId 等分页信息拉取接口至少5次, 并在state 中并保存合并对应itemId下的数据, 这里有两个步骤1,每次请求的数据在赋值给state之前 ,要获取到原有state中的值; 2,合并操作。那如何在reduce 中获取到原有state的值呢, 就是状态管理了.
redux
redux 本身非常简单,它只有三个核心概念:state、action 和 reducer, 直接看官网就可以了, 或者网上成堆的10 分钟理解 Redux。 将需要修改的 state 都存入到 store 里, 发起一个 action 用来描述发生了什么,用 reducers 描述 action 如何改变 state tree 。因此只有 reducer 能修改 state。redux 通过这些约束,让数据的变化变得可预测、可回溯。在创建 store 的时候需要传入 reducer,真正能改变 store 中数据的是 store.dispatch API。可以采用两种中间件redux-thunk 和redux-saga。 当然也可以直接使用ant design pro是基于UmiJS、dva,而 dva 也是基于 redux、redux-saga 和 react-router 的进一步封装。
redux-thunk
redux-thunk 中间件可以允许你写的 action creator 函数可以返回 action 对象的同时,也可以返回一个函数。函数传递两个参数 (dispatch,getState), 在函数体内进行业务逻辑的封装, getState() 方法获取 state
这个中间件可以被用来延缓分发 action 的时机,或者实现只在满足某个条件的时候才触发 action。简而言之,中间件都是对 store.dispatch () 的增强。以下是官网的一个例子
import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
const store = createStore(
reducers,
applyMiddleware(thunk)
);
// 而且可以使用 Promise 来控制数据流。
function makeSandwichesForEverybody() {
return function (dispatch, getState) {
if (!getState().sandwiches.isShopOpen) {
// 返回 Promise 并不是必须的,但这是一个很好的约定,
// 为了让调用者能够在异步的 dispatch 结果上直接调用 .then() 方法。
return Promise.resolve()
}
// 可以 dispatch 普通 action 对象和其它 thunk,
// 这样我们就可以在一个数据流中组合多个异步 action。
return dispatch(
makeASandwichWithSecretSauce('My Grandma')
).then(() =>
Promise.all([
dispatch(makeASandwichWithSecretSauce('Me')),
dispatch(makeASandwichWithSecretSauce('My wife'))
])
).then(() =>
dispatch(makeASandwichWithSecretSauce('Our kids'))
).then(() =>
dispatch(getState().myMoney > 42 ?
withdrawMoney(42) :
apologize('Me', 'The Sandwich Shop')
)
)
}
}
复制代码
以上就是异步 Action ,thunk 是判别 action 的类型,如果 action 是函数,就调用这个函数,但是函数的内部可以多种多样。比如下面是一个获取matching 中图片下面的信息的异步操作所对应的 action,然而需要为每一个异步操作都如此定义一个 action,显然 会有大量的action, 并且action 不易维护, 这是action 的副作用,也正是thunk 的缺点仅仅调用的函数。
redux-saga
官网上的描述redux-saga 是一个用于管理应用程序 Side Effect(副作用,例如异步获取数据,访问浏览器缓存等)的 library,它的目标是让副作用管理更容易,执行更高效,测试更简单
。 粗浅的使用后的感受是很强大-各种情况下的流程控制都有对应的api,这些api保证了更简便的流程控制和易于测试的好处,因 thunk 插件还是需要你自己来写promise来保证各种异步和异常。那redux-saga 中间件中如何获取state呢,更简单select(selector, ...args)
const keyList = yield select(state => {});
复制代码
几种常用的用法
Sagas 被实现为 Generator functions,一旦 Promise 被 resolve,middleware 会恢复 Saga 接着执行,直到遇到下一个 yield。 点击获取以下详细的demo例子
- put 用于创建 dispatch Effect。
takeEvery(pattern, saga, ...args)
在发起(dispatch)到 Store 并且匹配 pattern 的每一个 action 上派生一个 saga。- call 用于创建 Effect。发起异步或者同步操作
- select 用于创建一个 Effect, 返回当前 Store state 上的一部分数据
- fork 创建一个 Effect,用来命令 middleware 以 非阻塞调用 的形式执行 fn
- cacel 创建一个 Effect,用来命令 middleware 取消之前的一个分叉任务-之前 fork 指令返回的 Task 对象
import { createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'
//...
import { demoSaga } from './demoSagas'
const store = createStore(
reducer,
applyMiddleware(createSagaMiddleware(demoSaga))
)
import { delay } from 'redux-saga'
import { put, takeEvery } from 'redux-saga/effects'
// demoSagas.js
// Our worker Saga: 将执行异步的 获取用户信息
export function* getUser() {
const user = yield call(fetch, {
// method: "POST"
resource: ''
});
}
// Our watcher Saga:
const watchGet = function* watchGet() {
yield takeEvery(getUserRequested, getUser);
}
cnost getActions = {
[getUserRequested]: state => {
return {
...state,
isLogging: true
};
},
[getUserSucceed]: (state, { payload: { avatar, name, email } }) => {
return {
...state,
isLogging: false,
user: {
avatar,
name,
email
}
};
},
[getUserFailed]: state => {
return {
...state,
isLogging: false
};
}
};
// rootSaga.js
export default function* rootSaga() {
import { all, call } from 'redux-saga/effects';
import { watchAppSagas } from './reducers/demoReducer';
export const sagas = function* rootSaga() {
yield all(
[
...watchAppSagas,
].map(call)
);
};
复制代码