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>

posted @ 2021-07-07 16:48  85号bobo  阅读(512)  评论(0)    收藏  举报