浅读redux源码

1、源码结构

当前redux master分支已全部使用typescript,为便于理解可使用4.x分支,仍是js版本)

在这里插入图片描述

2、核心方法 createStore.js

  • 创建一个redux store掌管状态树
  • 改变store中数据的唯一方式就是调用dispatch()
  • 一个app中应该仅具有一个store,多个模块可以使用combineReducers合并不同的reducer

params & returns:

@param {Function} reducer

传入当前状态树和action,返回新的状态树

//reducer实例
const todos = (state = [], action) => {
  switch (action.type) {
    case 'ADD_TODO':
      return [
        ...state,
        {
          id: action.id,
          text: action.text,
          completed: false
        }
      ]
    case 'TOGGLE_TODO':
      return state.map(todo =>
        (todo.id === action.id)
          ? {...todo, completed: !todo.completed}
          : todo
      )
    default:
      return state
  }
}

@param{any} [preloadedState]

初始状态(可以用来进行状态回溯)

@param{Function} [enhancer]

通过第三方中间件增强能力,如redux-thunk增强异步dispatch的能力

@return {Store}

返回一个store

定义的5个变量
  let currentReducer = reducer
  let currentState = preloadedState
  let currentListeners = []
  let nextListeners = currentListeners
  let isDispatching = false

ensureCanMutateNextListeners()

防止在dispach过程中改变监听列表,所以用slice()做了一个复制

getState()

通过getState()获取currentState

subscribe(listener)

@param {function} listener
@return {function} unsunscribe()

添加一个listener监听函数,每次状态改变都会调用。
返回一个函数来取消监听。
通过nextListeners.splice(index)取消监听

    ensureCanMutateNextListeners()
    nextListeners.push(listener)
    //复制新数组,防止dispatch时的回调会改变当前listener数组
dispatch(action)

dispatch一个action。这是触发状态更改的唯一方法。
基本实现仅支持普通对象(异步promise需要中间件)

param {Object} action
return {Object}

实现过程

  • 调用util中的isPlainObject()判断action是否是"plain obj"
  • 判断action是否有type
  • 判断isDispatching,reducer中不能进行dispatch
  • 核心代码
try {
      isDispatching = true
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }
 const listeners = (currentListeners = nextListeners)
 for (let i = 0; i < listeners.length; i++) {
   const listener = listeners[i]
   listener()
    }
  • 每一次dispatch 会走一边全部的reducer
    (Reducer很多时可能存在性能问题)
  • 遍历调用listener()执行回调,过程中可能会改变linstener数组,不过在订阅阶段已经复制数组避免了这一问题。
replaceReducer()

将currentReducer替换为nextReducer

observable()

最小的可观察订阅方法。
@param {Object} 观察者 任何可以用作观察者的对象。
观察者对象应该有一个 next 方法。
@returns {subscription} 一个带有 unsubscribe 方法的对象,它可以
用于从 store 中取消订阅 observable,

3、combineReducers.js

@param {Object} reducers
@returns {Function}

核心思路

  • 通过key遍历参数reducers,替换finalReducer的key
  • 通过finalReducer的key,同样是for循环遍历执行每一个reducer。也就是说:对于多个 reducer ,一次 dispatch 会依次把所有 reducer 执行一次。

Q:如此设计,每次dispatch都要执行全部的reducer会不会有性能问题?
A:官方的回复:不会,但可以使用第三方库优化

However, even if you happen to have many different reducer functions
composed together, and even with deeply nested state, reducer speed is
unlikely to be a problem. JavaScript engines are capable of running a
very large number of function calls per second, and most of your
reducers are probably just using a switch statement and returning the
existing state by default in response to most actions.

If you actually are concerned about reducer performance, you can use a
utility such as redux-ignore or reduxr-scoped-reducer to ensure that
only certain reducers listen to specific actions. You can also use
redux-log-slow-reducers to do some performance benchmarking.

值得一提的是,代码中频繁出现的
process.env.NODE_ENV !== 'production'
node中,有全局变量process表示的是当前的node进程。
process.env包含着关于系统环境的信息,NODE_ENV是一个用户自定义的变量,用于判断生产环境或开发环境。

4、compose.js

@param {…Function} funcs 要组合的函数。
@returns {Function} 通过组合参数函数获得的函数 * 从右到左。例如,compose(f, g, h) 等同于做 * (…args) => f(g(h(…args)))。

有多个 enhancer 时,使用 compose 组装后传给 createStore。

核心代码

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return (arg) => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

此功能类似 _.flow([funcs])

5、applyMiddleware.js

@param {…Function} middlewares 要应用的中间件链。
@returns {Function} 应用中间件的store enhancer。

请注意,每个中间件都将被赋予 dispatchgetState 函数作为命名参数

核心代码

export default function applyMiddleware(...middlewares) {
  return (createStore) => (...args) => {
    const store = createStore(...args)
    let dispatch = () => {
      throw new Error(
        'Dispatching while constructing your middleware is not allowed. ' +
          'Other middleware would not be applied to this dispatch.'
      )
    }

    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args),
    }
    const chain = middlewares.map((middleware) => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch,
    }
  }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React Redux是一个用于在React应用中管理状态的库。它结合了ReactRedux,提供了一种可预测的状态管理解决方案。在React Redux中,我们使用Provider组件将Redux的store传递给整个应用程序,以便在应用程序的任何地方都可以访问到Redux的状态。\[1\]\[3\] 在React Redux中,我们可以使用connect函数将组件连接到Redux的store,并将store中的状态映射到组件的props上。这样,组件就可以通过props访问和更新Redux的状态。同时,我们还可以使用dispatch函数来触发Redux中的action,从而更新状态。\[2\] 通过React Redux,我们可以更方便地管理React应用的状态,使得应用的状态变化更加可控和可预测。同时,React Redux还提供了一些中间件,如Redux-thunk,可以帮助我们处理异步操作,使得应用的状态管理更加灵活和强大。\[2\] 总之,React Redux是一个强大的状态管理库,可以帮助我们更好地管理React应用的状态,并提供了一些工具和中间件来简化状态管理的过程。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* *3* [React中的Redux](https://blog.csdn.net/yrqlyq/article/details/119118182)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值