程式碼分割
在大型網路應用程式中,通常希望將應用程式程式碼分割成多個 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")
函式庫和架構
有幾個不錯的函式庫可以協助您自動加入上述功能