跳至主要內容

程式碼分割

在大型網路應用程式中,通常希望將應用程式程式碼分割成多個 JS 捆綁檔,以便依需求載入。此策略稱為「程式碼分割」,有助於透過減少必須擷取的初始 JS 酬載大小來提升應用程式的效能。

若要使用 Redux 進行程式碼分割,我們希望能夠動態將還原器新增至儲存。然而,Redux 實際上只有一個單一根還原器函式。此根還原器通常是在應用程式初始化時,透過呼叫 combineReducers() 或類似的函式來產生。若要動態新增更多還原器,我們需要再次呼叫該函式以重新產生根還原器。以下我們將討論一些解決此問題的方法,並參考兩個提供此功能的函式庫。

基本原則

使用 replaceReducer

Redux store 顯示一個 replaceReducer 函式,它會用一個新的根部 reducer 函式取代目前作用中的根部 reducer 函式。呼叫它會交換內部 reducer 函式參考,並發送一個動作,以協助任何新加入的區塊 reducer 初始化它們自己

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

store.replaceReducer(newRootReducer)

Reducer 注入方法

定義一個 injectReducer 函式

我們可能會想要從應用程式的任何地方呼叫 store.replaceReducer()。因此,定義一個可重複使用的 injectReducer() 函式會很有幫助,它會保留所有現有區塊 reducer 的參考,並將其附加到 store 實例。

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 加入 store。

使用「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")

函式庫和架構

有幾個不錯的函式庫可以協助您自動加入上述功能