我有一个独特的情况,我的<Provider>
组件(和整个Redux Store)从一个中间件应用程序导出到多个前端React应用程序。中间件有自己的reducer集合,但是客户端应用可以在调用提供商时将自己的reducer注入到store中。
现在被要求在调用Provider时接受一个初始状态(preloaddstate)对象,以便应用程序的初始状态可以加载为动态初始状态。这个对象将是一个任意的状态数据集(带有相应的reducer),所以我将在reducer中拥有正确的形状数据结构,但我不知道它们发送的是什么值。
下面是基本的ReduxStore设置,为了简单起见在这里做了修改:
ReduxStore.ts
import { configureStore } from '@reduxjs/toolkit';
import { ExampleReducer } from './slices/ExampleSlice';
export const reducer = {
example: ExampleReducer
};
const ReduxStore = configureStore({
middleware: ...,
reducer,
});
export default ReduxStore;
CoreProvider.tsx
import React from 'react';
import { Provider } from 'react-redux';
import { combineReducers, ReducersMapObject, AnyAction } from '@reduxjs/toolkit';
import ReduxStore, { reducer } from './ReduxStore';
export type ConfigProps = {
newReducers?: ReducersMapObject<unknown, AnyAction>;
preloadedState: Object;
};
const CoreProvider: React.FC<ConfigProps> = ({
children,
newReducers,
}) => {
const newReducer = combineReducers({ ...newReducers, ...reducer });
ReduxStore.replaceReducer(newReducer);
return <Provider store={ReduxStore}>{children}</Provider>;
};
export default CoreProvider;
index.jsx
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<CoreProvider newReducers={{ arbitrary: arbitraryReducer }}>
<App />
</CoreProvider>
</React.StrictMode>,
);
现在,我意识到我不应该这样做的原因,我也意识到初始状态来自于reducer本身,当调用Provider时,当reducer与默认reducer合并时,它会被处理。
我知道configureStore接受preloaddstate选项,但我卡住的地方是如何动态地传递preloaddstate作为Provider组件的prop。我尝试在Provider组件中调用的函数中包装configureStore调用,该函数确实设置了初始状态,但我的ReduxStore导出在ReduxStore中。由于应用程序加载的方式和configureStore被调用的方式,ts未定义。
使用preloaddstate props调用configureStore的提供商:
import { initReduxStore, reducer } from './ReduxStore';
const CoreProvider: React.FC<ConfigProps> = ({
children,
newReducers,
preloadedState
}) => {
const newReducer = combineReducers({ ...newReducers, ...reducer });
const ReduxStore = initReduxStore(preloadedState, newReducer);
return <Provider store={ReduxStore}>{children}</Provider>;
};
export default CoreProvider;
ReduxStore与导出configureStore功能和未定义的ReduxStore导出:
export const reducer = {
example: ExampleReducer
};
let ReduxStore;
export const initReduxStore = (incomingState, incomingReducer) => {
if (ReduxStore) return ReduxStore;
const store = configureStore({
middleware: ...,
preloadedState: incomingState,
reducer: incomingReducer,
});
ReduxStore = store;
return ReduxStore;
};
export default ReduxStore; // This becomes undefined because the file loads before the Provider component calls the initReduxStore function
ReduxStore导出是未定义的,因为文件在Provider组件调用initReduxStore函数之前加载,并且ReduxStore在导出时是未定义的。
是否有一种已知的方法,我忽略了容易设置预加载状态对象时,调用提供程序?我是否应该重新构建ReduxStore的创建方式?
在短期内,我如何获得preloaddstate prop从我的提供者到我的configureStore,同时仍然导出ReduxStore到应用程序的其余部分?
export const ReduxStore = configureStore({
preloadedState,
reducer,
});
// HOW DO I CONNECT THESE
const CoreProvider: React.FC<ConfigProps> = ({
children,
newReducers,
preloadedState
}) => {
return <Provider store={store}>{children}</Provider>;
};
export default CoreProvider;
欢迎大家多多指教。
简短的回答是,你不能。preloadedState
选项只能在调用configureStore()
时传入。一旦创建了存储,唯一更新存储状态的方法就是调度一个操作。
最重要的是,诸如替换reducer或分派动作之类的行为将被视为副作用,并且React组件必须不能在呈现逻辑中直接具有副作用。
我最接近的建议是在这个组件中使用useLayoutEffect
钩子,它监视所提供的reducer或状态的变化,并执行store.replaceReducer()
调用。
同样,你可以有一个换行减速器,在这个附加状态中监视某种"合并"。操作,并返回带有附加字段的更新状态。
但总的来说,这是一个非常不寻常的用例,并不是Redux真正设计的。