redux 是否可以使用RTK configureStore动态设置preloadedState?

xwbd5t1u  于 2023-01-13  发布在  其他
关注(0)|答案(1)|浏览(192)

我有一个独特的情况,我的<Provider>组件(和整个Redux Store)从中间件应用导出到多个前端React应用。中间件有自己的Reducer集,但客户端应用可以在调用提供程序时将自己的Reducer注入到商店中。
现在,当调用Provider时,我需要接受一个初始状态(preloadedState)对象,以便应用的初始状态可以动态加载。这个对象将是任意的状态数据集(带有相应的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接受preloadedState选项,但我遇到的问题是如何动态传递从Provider组件作为prop传入的preloadedState。我曾尝试将configureStore调用 Package 在Provider组件内调用的函数中,该函数确实设置了初始状态,但由于应用加载和调用configureStore的方式,我在ReduxStore.ts中的ReduxStore导出未定义。
提供程序使用preloadedState属性调用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;

具有导出的configureStore函数和未定义ReduxStore导出的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的创建方式吗?
简言之,如何将preloadedState属性从Provider导入到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;

任何想法都很感激。

gxwragnw

gxwragnw1#

简短的回答是,你不能。preloadedState选项只能在你调用configureStore()时传入。一旦创建了存储,更新存储状态的唯一方法就是分派一个动作。
除此之外,替换Reducer或分派动作等行为将被视为副作用,React组件 * 不得 * 在渲染逻辑中直接具有副作用。
我的最接近的建议是在这个组件中使用一个useLayoutEffect钩子来监视所提供的reducer或状态的变化,并执行store.replaceReducer()调用。
此外,您还可以使用一个 Package 缩减器来监视某种类型的“merge in this additional state”操作,并返回带有附加字段的更新状态。
但总的来说,这是一个非常不寻常的用例,Redux并不是真正为之设计的。

相关问题