reactjs - 將 Redux Toolkit 通用高階 reducer 組合成具有意義的狀態層級,並使用 configureStore
我正在回到 Redux + Redux Toolkit 來管理一些 React 應用程式的狀態。
我正在嘗試理解通用 reducers,特別是針對共享相同 reducer 邏輯和狀態結構的 state 切片。也就是所謂的「已上傳文件」切片,表示已經上傳到伺服器/本地存儲的文件。在閱讀了文檔中關於重用 reducer 邏輯的這一部分後,我設計出了這個高階 reducer:
import { createSlice, PayloadAction, SliceCaseReducers, ValidateSliceCaseReducers } from '@reduxjs/toolkit'
interface UploadFilesState {
files: {
type: 'font'|'image'
fileName: string
filePath: string
}[]
maxFiles: number
}
export const createUploadFilesSlice = <
Reducers extends SliceCaseReducers<UploadFilesState>
>({
name = '',
initialState,
reducers,
}: {
name: string
initialState: UploadFilesState
reducers?: ValidateSliceCaseReducers<UploadFilesState, Reducers>
}) => {
return createSlice({
name,
initialState,
reducers: {
fileUploaded(state: UploadFilesState, action: PayloadAction<UploadFilesState['files'][0]>) {
if (state.files.length < state.maxFiles) {
state.files.push(action.payload)
}
},
...reducers,
},
})
}
但我對如何將它與 configureStore() 以及我想要的狀態結構一起使用感到困惑。例如,我的全局狀態應該看起來像這樣:
// Written as a Typescript interface to visualise the shape of the store
{
appName: string
defaults: {
background: {
colour: string
images?: /* Using my generic uploadFileSlice here */
}
fonts: /* Using my generic uploadFileSlice here */
}
}
我如何使用 Redux Toolkit 的 configureStore() 方法來利用我的通用 slice?例如,像這樣的方式:
export default configureStore({
reducer: {
appName: /* Some string reducer */
defaults: {
background: {
colour: /* some colour reducer */
images: createUploadFilesSlice({ name: 'defaultBackgroundImages', initialState: { files: [], maxFiles: 1}})
}
fonts: createUploadFilesSlice({ name: 'defaultFonts', initialState: { files: [], maxFiles: 2}})
}
},
})
上述拋出。是不是我不可以這樣在物件字面量中巢狀使用 reducers?我是否應該改為創建像這樣非常平坦的結構:
{
appName: string
defaultBackgroundColour: string
defaultBackgroundImages: /* Using my generic uploadFileSlice here */
defaultFonts: /* Using my generic uploadFileSlice here */
}
自從我使用 Redux 已經有一段時間了,所以我不熟悉它的限制是什麼。
答案#1
這裡的主要問題是 Redux 核心的 combineReducers 方法不是遞歸的——它接受一個只包含單層 sliceName: someSliceReducer 配對的物件。當在 configureStore 中的 reducer 欄位給定一個物件時,它實際上只是將這個物件傳給 combineReducers,所以你不需要自己去呼叫它。
如果你想要以這種方式有一些額外的巢狀層級,你需要自己調用 combineReducers 幾次,就像這樣:
const backgroundReducer = combineReducers({
color: colorReducer,
images: createSomeReusableReducer("images")
})
const defaultsReducer = combineReducers({
background: backgroundReducer,
fonts: createSomeReusableReducer("fonts")
})
const store = configureStore({
reducer: {
appName: appNameReducer,
defaults: defaultsReducer
}
})
