跳至主要内容

代码拆分

在大型 Web 应用程序中,通常希望将应用程序代码拆分为多个可以按需加载的 JS 包。这种策略称为“代码拆分”,通过减少必须获取的初始 JS 负载的大小来帮助提高应用程序的性能。

要使用 Redux 进行代码拆分,我们希望能够动态地将 reducer 添加到商店中。但是,Redux 实际上只有一个根 reducer 函数。这个根 reducer 通常是在应用程序初始化时通过调用 combineReducers() 或类似函数生成的。为了动态添加更多 reducer,我们需要再次调用该函数以重新生成根 reducer。下面,我们将讨论解决此问题的一些方法,并参考两个提供此功能的库。

基本原理

使用 replaceReducer

Redux 存储提供了一个 replaceReducer 函数,它用新的根 reducer 函数替换当前活动的根 reducer 函数。调用它将交换内部 reducer 函数引用,并分派一个操作来帮助任何新添加的切片 reducer 初始化自身。

const newRootReducer = combineReducers({
existingSlice: existingSliceReducer,
newSlice: newSliceReducer
})

store.replaceReducer(newRootReducer)

Reducer 注入方法

定义一个 injectReducer 函数

我们可能希望从应用程序中的任何地方调用 store.replaceReducer()。因此,定义一个可重用的 injectReducer() 函数来保存所有现有切片 reducer 的引用,并将该函数附加到存储实例非常有用。

import { createStore } from 'redux'

// Define the Reducers that will always be present in the application
const staticReducers = {
users: usersReducer,
posts: postsReducer
}

// Configure the store
export default function configureStore(initialState) {
const store = createStore(createReducer(), initialState)

// Add a dictionary to keep track of the registered async reducers
store.asyncReducers = {}

// Create an inject reducer function
// This function adds the async reducer, and creates a new combined reducer
store.injectReducer = (key, asyncReducer) => {
store.asyncReducers[key] = asyncReducer
store.replaceReducer(createReducer(store.asyncReducers))
}

// Return the modified store
return store
}

function createReducer(asyncReducers) {
return combineReducers({
...staticReducers,
...asyncReducers
})
}

现在,只需要调用 store.injectReducer 就可以将新的 reducer 添加到存储中。

使用“Reducer 管理器”

另一种方法是创建一个“Reducer 管理器”对象,它跟踪所有注册的 reducer 并公开一个 reduce() 函数。请考虑以下示例

export function createReducerManager(initialReducers) {
// Create an object which maps keys to reducers
const reducers = { ...initialReducers }

// Create the initial combinedReducer
let combinedReducer = combineReducers(reducers)

// An array which is used to delete state keys when reducers are removed
let keysToRemove = []

return {
getReducerMap: () => reducers,

// The root reducer function exposed by this object
// This will be passed to the store
reduce: (state, action) => {
// If any reducers have been removed, clean up their state first
if (keysToRemove.length > 0) {
state = { ...state }
for (let key of keysToRemove) {
delete state[key]
}
keysToRemove = []
}

// Delegate to the combined reducer
return combinedReducer(state, action)
},

// Adds a new reducer with the specified key
add: (key, reducer) => {
if (!key || reducers[key]) {
return
}

// Add the reducer to the reducer mapping
reducers[key] = reducer

// Generate a new combined reducer
combinedReducer = combineReducers(reducers)
},

// Removes a reducer with the specified key
remove: key => {
if (!key || !reducers[key]) {
return
}

// Remove it from the reducer mapping
delete reducers[key]

// Add the key to the list of keys to clean up
keysToRemove.push(key)

// Generate a new combined reducer
combinedReducer = combineReducers(reducers)
}
}
}

const staticReducers = {
users: usersReducer,
posts: postsReducer
}

export function configureStore(initialState) {
const reducerManager = createReducerManager(staticReducers)

// Create a store with the root reducer function being the one exposed by the manager.
const store = createStore(reducerManager.reduce, initialState)

// Optional: Put the reducer manager on the store so it is easily accessible
store.reducerManager = reducerManager
}

要添加新的 reducer,现在可以调用 store.reducerManager.add("asyncState", asyncReducer)

要删除 reducer,现在可以调用 store.reducerManager.remove("asyncState")

库和框架

有一些很好的库可以帮助您自动添加上述功能。