react: Redux、React-Redux、Redux-Thunk、Redux-Saga用法
React: Redux、React-Redux、Redux-Thunk、Redux-Saga用法
Redux
当组件需要改变store内的数据时,就发送一个action给到store,store收到action后就会调用相应的reducers函数,reducers函数会返回一个新的对象来作为新的数据值回传给store,之后组件再从store里面获取更新后的数据了。
三大原则
1,单一数据源
2,stata 只读
3,使用纯函数执行修改
基础概念
1,Store
store 就是保存数据state的地方,全局只有一个store,使用 createStore 来生成store
2,State
store对象包含所有数据,如果想得到某个时点的数据,就要对store生成快照。这种时点的数据集合,就叫state。
可通过store.getState()拿到当前时刻的state。
一个 state 只对应一个view。
3,action
State 的变化,会导致 View 的变化。用户通过改变 View 去改变 State。Action 就是 View 发出的通知,表示 State 应该要发生变化了。
View 通过 store.dispatch() 发出 Action 通知。
并且action 内必须使用一个字符串类型的 type 字段来表示将要执行的动作(规定action对象里面必须有type字段,否则代码将报错)
4,reducers
纯函数 - 只要是同样的输入,必定得到同样的输出
actions 只是描述了有事情发生,并没有描述应用如何更新state,而是有reducers根据action对象内的信息来改变store内的数据。
5,store.subscribe()
Store 允许使用 store.subscribe 方法设置监听函数,一旦state发生改变,就自动执行这个函数。
只要把 View 的更新函数(对于 React 项目,就是组件的render方法或setState方法)放入listen,就会实现 View 的自动渲染。
store.subscribe方法返回一个函数,调用这个函数就可以解除监听。
🌰
<图:redux/redux.js>

<图:view/redux.js>

React-Redux
react-redux 是 redux 的一个插件库,专门用来简化 react 应用中的 redux。
react-redux 将所有组件分成两大类:
- UI组件
1,只负责UI展示,没有业务逻辑
2,无状态,所有数据由props提供
3,不使用任何redux 的API - 容器组件
1,只负责数据和业务逻辑,无UI
React-Redux 规定,所有的 UI 组件都由用户提供,容器组件则是由 React-Redux 自动生成(由connect()函数生成)
react-redux 通过 provider 组件做到了store的统一管理,并利用 connect 包裹组件生成容器组件与store打通数据流,这样就不需要在每个组件中引入store,并监听store,使用更方便
react-redux 对redux 对简化主要在四个API:
- provider
该组件把根组件包含起来,并且provider组件需要传入store,这样一来所有组件都可以得到state数据
<Provider store={store}>
<App />
</Provider>
- connect
用于包装 UI组件 生成 容器组件,connect方法接受两个参数: mapStateToProps、mapDispatchToProps、mergeProps、options
connect(
mapStateToprops,
mapDispatchToProps
)(UIComponent)
-
mapStateToprops
负责输入逻辑,即将state映射到 UI 组件的参数(props),把store的 state 挂载到组件的 props 上,是一个函数 -
mapDispatchToProps
输出逻辑,即将用户对 UI 组件的操作映射成 Action,即 UI 组件的参数到store.dispatch方法的映射,把dispatch触发action的函数挂载到props上,可以是一个函数,也可以是对象 -
mergeProps
[mergeProps(stateProps, dispatchProps, ownProps): props]
不管是stateProps还是dispatchProps,都需要和ownProps merge 之后才会被赋给MyComp。connect的第三个参数就是用来做这件事。通常情况下,你可以不传这个参数,connect就会使用Object.assign替代该方法。 -
options
基本不会用到
🌰
注:在根组件中使用 Provide 注入store
<图:redux/react-redux.js>

<图:view/react-redux.js>

Redux-Thunk
redux-thunk 处理异步的中间件
dispatch 一个 action 之后,在到达 reducer 之前进行一些额外的操作
Redux 的中间件提供的是位于 View 发出 action 通知之后,到达 reducer 之前的扩展点
由原本的: view -> action -> reducer -> store
变成了:view -> action -> middleware -> reducer -> store
在这一环节我们可以做一些 “副作用” 的操作,如 异步请求、打印日志等。
将thunk中间件引入,放在applyMiddleware方法之中,传入createStore方法,就完成了store.dispatch()的功能增强。即可以在reducer中进行一些异步的操作
const store = createStore(reducer, applyMiddleware(thunk))
applyMiddleware
Redux的一个原生方法,将所有中间件组成一个数组,依次执行。 中间件多了可以当做参数依次传进去
- 缺点
thunk仅仅做了执行这个函数,并不在乎函数主体内是什么,也就是说thunk使 得redux可以接受函数作为action,但是函数的内部可以多种多样,这就导致了 action 不易维护的缺点:
1,action的形式不统一
2,异步操作太为分散,分散在了各个action中
redux-thunk 源码
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
🌰
注:在根组件中使用 Provide 注入store
<图:redux/redux-thunk.js>

<图:view/redux-thunk.js>

Redux-Saga
redux-saga 处理异步
redux-saga 是通过 generator 实现的,用于管理 Redux 应用异步操作的中间件
通过创建 Sagas 将所有的异步操作逻辑收集在一个地方集中处理,可以用来代替 redux-thunk 中间件。
action1 —>redux-saga监听 —> 执行相应的Effect方法 —> 返回描述对象—> 恢复执行异步和副作用函数 —> action2
createSagaMiddleware
创建一个 Redux 中间件,将 Sagas 和 redux store链接起来
Sagas 与 thunks:
1,thunks 是在 action 被创建的时候调用
Sagas 只会在应用启动的时候调用(但初始启动的 Sagas 可能会动态调用其他 Sagas),Sagas 监听发起的action,然后决定基于这个 action来做什么:是发起一个异步调用(比如一个 fetch 请求),还是发起其他的action到Store,甚至是调用其他的 Sagas
2,在 redux-saga 的世界里,所有的任务都通用 yield Effects 来完成(Effect 可以看作是 redux-saga 的任务单元)
Sagas API
- takeEvery
允许多个实例同时启动,依次执行 - takeLatest
允许多个实例同时启动,但是只得到最新那个请求的响应 - take(pattern)
take函数可以理解为监听未来的action,它创建了一个命令对象,告诉middleware等待一个特定的action, Generator会暂停,直到一个与pattern匹配的action被发起,才会继续执行下面的语句,也就是说,take是一个阻塞的 effect - put(action)
put函数是用来发送action的 effect,你可以简单的把它理解成为redux框架中的dispatch函数,当put一个action后,reducer中就会计算新的state并返回,注意: put 也是阻塞 effect - call(fn, ...args)
call函数你可以把它简单的理解为就是可以调用其他函数的函数,它命令 middleware 来调用fn 函数, args为函数的参数,注意: fn 函数可以是一个 Generator 函数,也可以是一个返回 Promise 的普通函数,call 函数也是阻塞 effect - fork(fn, ...args)
fork 函数和 call 函数很像,都是用来调用其他函数的,但是fork函数是非阻塞函数,也就是说,程序执行完 yield fork(fn, args) 这一行代码后,会立即接着执行下一行代码语句,而不会等待fn函数返回结果后,在执行下面的语句 - select(selector, ...args)
select 函数是用来指示 middleware 调用提供的选择器获取Store上的state数据,你也可以简单的把它理解为redux框架中获取store上的 state数据一样的功能 :store.getState()
let counter = yield select(state => state.counter)
🌰
注:在根组件中使用 Provide 注入store
<图:redux/redux-saga.js>

<图:view/redux-saga.js>


浙公网安备 33010602011771号