Redux源码分析--CreateStore(subscribe)

Redux源码分析:

上一章介绍了Redux源码分析--CreateStore(getState、subscribe),这一次介绍subscribe及其注销监听事件。如果分析的有问题,请及时提醒,谢谢。

整个createStore.js代码中真正影响到store.subscribe(listener)的有以下几个:

  • let currentListeners = []; let nextListeners = currentListeners;
  • subscribe方法
  • ensureCanMutateNextListeners方法
  • dispatch方法中监听事件的循环执行

let currentListeners = []; let nextListeners = currentListeners; 好理解,就是执行createStore()时,简单的变量初始化,让currentListeners和nextListeners指针指向同一个空数组。

ensureCanMutateNextListeners

    这个方法作用:当currentListeners和nextListeners指向同一个数组时,就会给nextListeners指向另外一个数组(currentListeners.slice()返回的数组)

下面介绍一下为啥需要两个变量来处理listeners监听事件,如有问题,请提醒,谢谢

    为什么需要用两个变量来定义listeners监听事件呢?比如:如果只有一个变量存放listeners时,在dispatch方法中,循环执行listeners,要是在某个listener监听事件中,删除某个监听事件,这样就会可能会影响另外监听事件的执行。下面用实例来说明下这个问题:

我们先正常情况下,循环运行a/b/c方法,打印出:a b c

let a = () => {console.log('a')};
let b = () => {console.log('b')};
let c = () => {console.log('c')};
let listeners = [a, b, c];
for(let i=0; i<listeners.length; i++) {
	let listener = listeners[i];
	listener();
}

之后,在考虑在执行函数中,注销掉某个方法,实例如下:

let a = () => {console.log('a')};
let c = () => {console.log('c')};
let listeners = [a];
let b = () => {
	if(listeners.indexOf(c) > -1) {
		const index = listeners.indexOf(c)
      	listeners.splice(index, 1)
	}
	console.log('b')
};

listeners.push(b);
listeners.push(c);

for(let i=0; i<listeners.length; i++) {
	let listener = listeners[i];
	listener();
}

返回结果:a b

剩下的关于subscribe方法,里面的代码就比较简单了。可以说,subscribe是一个闭包函数

subscribe内部代码实现:

  • 判断store.subscribe(listener)中listener是不是一个函数,如果否,则抛出一个错误“Expected the listener to be a function”
  • 当isDispatching等于true(当reducer在执行的时候)的时候,执行store.subscribe(listener),抛出一个异常
  • isSubscribe变量用于判断当前监听事件是否已经注销
  • 执行ensureCanMutateNextListeners
  • 将listener push到nextListeners里
  • 返回一个函数(目的是去注销当前监听事件)
function subscribe(listener) {
    if (typeof listener !== 'function') {
      throw new Error('Expected the listener to be a function.')
    }

    if (isDispatching) {
      throw new Error(
        'You may not call store.subscribe() while the reducer is executing. ' +
          'If you would like to be notified after the store has been updated, subscribe from a ' +
          'component and invoke store.getState() in the callback to access the latest state. ' +
          'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'
      )
    }

    let isSubscribed = true

    ensureCanMutateNextListeners()
    nextListeners.push(listener)

    return function unsubscribe() {
      if (!isSubscribed) {
        return
      }

      if (isDispatching) {
        throw new Error(
          'You may not unsubscribe from a store listener while the reducer is executing. ' +
            'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'
        )
      }

      isSubscribed = false

      ensureCanMutateNextListeners()
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
    }
  }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue 3 的状态管理库 Pinia 和 Redux 的持久化库 redux-persist 的结合使用可以实现在 Vuex 使用的持久化存储功能。 首先,安装依赖: ```shell npm install pinia redux-persist ``` 然后在 `src/store/index.ts` 引入 Pinia 和 redux-persist: ```typescript import { createPinia } from 'pinia' import { persist } from 'pinia-plugin-persist' import { createStore } from 'redux' import { persistStore, persistReducer } from 'redux-persist' import storage from 'redux-persist/lib/storage' const pinia = createPinia() // 定义 Pinia 插件,使用 redux-persist 进行持久化存储 pinia.use( persist({ // 持久化存储的 key key: 'pinia', // 持久化存储的引擎,默认使用 localStorage storage, // 将 Pinia 的状态转换为 Redux 的状态 reducer: (state: any) => state.value, // 将 Redux 的状态转换为 Pinia 的状态 restoreState: (reduxState: any) => ({ value: reduxState }), }) ) // 定义 Redux 的 reducer const reducer = (state = 0, action: any) => { switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 default: return state } } // 创建 Reduxstore const store = createStore( persistReducer({ key: 'redux', storage }, reducer), undefined, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() ) // 持久化存储 Reduxstore const persistor = persistStore(store) export { pinia, store, persistor } ``` Pinia 插件使用 redux-persist 的 `persistReducer` 方法将 Pinia 的状态转换为 Redux 的状态,并进行持久化存储;`restoreState` 方法则将 Redux 的状态转换为 Pinia 的状态。 在应用使用 Pinia 时,可以直接使用 Pinia 的 API 进行状态管理,也可以通过 Redux 的 API 进行状态管理。例如,在 `src/App.vue` : ```vue <template> <div> <div>Pinia: {{ $pinia.state.value }}</div> <div>Redux: {{ $store.getState() }}</div> <button @click="$pinia.state.value++">Pinia +</button> <button @click="$pinia.state.value--">Pinia -</button> <button @click="$store.dispatch({ type: 'INCREMENT' })">Redux +</button> <button @click="$store.dispatch({ type: 'DECREMENT' })">Redux -</button> </div> </template> <script setup> import { useStore } from 'vuex' import { usePinia } from 'pinia' import { store, persistor } from './store' // 注册 Pinia 的 store const pinia = usePinia() pinia.useStore(store) // 注册 Reduxstore const vuexStore = useStore() vuexStore.replaceState(persistor.getState()) store.subscribe(() => { vuexStore.replaceState(persistor.getState()) }) </script> ``` 在应用同时使用 Pinia 和 Redux 时,需要注意 Pinia 和 Redux 的状态同步。在上面的例子,Pinia 和 Redux 的状态都被持久化存储,因此在应用重新加载时,需要将 Redux 的状态从持久化存储恢复,并将其转换为 Pinia 的状态。在 `script setup` ,通过 `useStore` 获取 Vuex 的 store,并使用 `replaceState` 方法将 Redux 的状态设置为 Vuex 的状态;`store.subscribe` 方法监听 Redux 的状态变化,并在变化时将 Redux 的状态设置为 Vuex 的状态。这样,在应用使用 Pinia 的 API 进行状态管理时,Pinia 和 Redux 的状态就是同步的。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值