react-redux

1
open
sqshada
sqshada
Posted 4 months ago

react-redux #26

redux 三大原则

  • 单向数据流
  • state 只读:如果想要改变 state,只能触发 action 执行 reducer
  • 纯函数执行:每个 reducer 都是一个纯函数,里面不要执行任何副作用,返回值作为新的 state,state 会触发 store 中的 subscribe

发布订阅思想

中间件思想

redux 应用了中间件 compose,中间件的作用是 强化 dispatch ,传统的 dispatch 是不支持异步的,但是可以针此点做强化,比如 redux-thunkredux-actions 等中间件。

dva 也写了一个 redux 支持 promise 的中间件

const compose = (...funcs) => {
  return funcs.reduce((f, g) => (x) => f(g(x)));
}

redux 核心 api

createStore

创建一个 store,将 store 传递给 React 应用。

const Store = createStore(rootReducer,initialState,middleware)

combineReducers

合并多个 reducers

/* 将 number 和 PersonalInfo 两个reducer合并   */
const rootReducer = combineReducers({ number:numberReducer,info:InfoReducer })

applyMiddleware

注册中间件,支持多个参数,每个参数都是一个中间件,每次出发 action,中间件执行

const middleware = applyMiddleware(logMiddleware)

React-Redux

Provider

Provider 作用就是保存 redux 中的 store,分配给需要 state 的子孙组件

connect

React-Redux 提供高阶组件 connect,被包裹后提供如下功能

  • 能够从 props 中获取改变 state 的方法 Store.dispatch
  • 如果 connect 有第一个参数,那么会将 redux state 中的数据,映射到当前组件的 props 中,子组件可以消费
  • 当需要的 state 有变化的时候,会通知当前组件更新,重新渲染视图
function connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?)

mapStateToProps

const mapStateToProps = state => ({ number: state.number })

组件依赖 redux 的 state,映射到业务的 props 中。

mapDispatchToProps

const mapDispatchToProps = dispatch => {
  return {
    numberAdd: () => dispatch({ type: 'ADD' }),
    setInfo: () => dispatch({ type: 'SET' }),
  }
}

将 redux 中的 dispatch 方法,映射到业务组件的 props 中。

mergeProps

/*
* stateProps , state 映射到 props 中的内容
* dispatchProps, dispatch 映射到 props 中的内容。
* ownProps 组件本身的 props
*/
(stateProps, dispatchProps, ownProps) => Object

options

{
  context?: Object,   // 自定义上下文
  pure?: boolean, // 默认为 true , 当为 true 的时候 ,除了 mapStateToProps 和 props ,其他输入或者state 改变,均不会更新组件。
  areStatesEqual?: Function, // 当pure true , 比较引进store 中state值 是否和之前相等。 (next: Object, prev: Object) => boolean
  areOwnPropsEqual?: Function, // 当pure true , 比较 props 值, 是否和之前相等。 (next: Object, prev: Object) => boolean
  areStatePropsEqual?: Function, // 当pure true , 比较 mapStateToProps 后的值 是否和之前相等。  (next: Object, prev: Object) => boolean
  areMergedPropsEqual?: Function, // 当 pure 为 true 时, 比较 经过 mergeProps 合并后的值 , 是否与之前等  (next: Object, prev: Object) => boolean
  forwardRef?: boolean, //当为true 时候,可以通过ref 获取被connect包裹的组件实例。
}
sqshada
sqshada
Created 4 months ago
  • React-Redux 通过上下文来保存传递 Store,但是上下文保存的还有 subscription
  • subscription 可以理解为订阅器,订阅 state 的变化,另一方面通知对应的组件更新。Provider 中的订阅器为根订阅器
  • 在 Provider 中,进行真正的绑定订阅功能,其原理内部调用了 store.subscribe
  • 订阅器的核心:层层订阅,上订下发
    • 每一个 connect 包装的组件内部也有一个 subscription。
    • 调用 trySubscription 时,订阅器会和上一级订阅器建立关联,store 中 state 的变化只会通知给 Provider 中的根订阅器。根 subscription 不会派发更新,而是下发给子代订阅器。
    • 子代订阅器通过浅比较 props 来判断 state 是否变化,如果变化直接触发一个 useReducer 来更新组件。

为什么 React-Redux 会采用 subscription 订阅器进行订阅,而不是直接采用 store.subscribe 呢 ?

  • 首先 state 的改变,Provider 是不能直接下发更新的,如果下发更新,那么这个更新是整个应用层级上的,还有一点,如果需要 state 的组件,做一些性能优化的策略,那么该更新的组件不会被更新,不该更新的组件反而会更新了。
  • 父 Subscription -> 子 Subscription 这种模式,可以逐层管理 connect 的状态派发,不会因为 state 的改变而导致更新的混乱。