如何手动将操作分派到使用 configureStore 创建的商店?

How do I manually dispatch actions to a store created with configureStore?

我有一个项目,其中一半是用 classes 制作的,另一半是用 hooks 和 Redux 制作的。 为此,我使用 Redux Toolkit 中的 configureStore() 创建了一个商店,并使用 Provider 组件提供了它。以极简的方式,商店设置如下:

const userSlice = createSlice({
    name: 'user',
    initialState: {
        user: {}
    },
    reducers: {
        validate: (state, action) => state.user = action.payload
    }
})

const store configureStore({
    reducer: {
        user: userSlice.reducer
    }
})

有两个组件 - 一个新的,功能性的,它使用 useSelector() 钩子,和一个旧的,它基于 class,但需要使用这个 sasme 商店来调度一个行动。 为此,我导入商店并启动

store.dispatch({type: 'user/validate', payload: newUser});

来自 class 组件。 我没有收到任何错误,但什么也没有发生。

我从 DevTools 的 Redux 插件跟踪了我的输入,我可以看到状态没有改变,所以我假设我对 dispatch 的手动调用有些错误。

我期望发生的是状态更新,这将触发使用 useSelector

的组件的重新渲染

以下方法是一种安全的分派操作的方法,不会拼错类型字符串。

  1. 从reducer中提取action
const userSlice = createSlice({
    name: 'user',
    initialState: {
        user: {}
    },
    reducers: {
        validate: (state, action) => {
            state.user = action.payload
          }
    }
})

// <------------------
// Action creators are generated for each case reducer function
export const { validate } = userSlice.actions


export const store =  configureStore({
    reducer: {
        user: userSlice.reducer
    }
})

  1. 按原样发送操作
store.dispatch(validate(newUser))

问题

我要说的是,问题是您正试图在 reducer 函数 中同时改变状态对象 return它。

Mutating and Returning State

In any given case reducer, Immer expects that you will either mutate the existing state, or construct a new state value yourself and return it, but not both in the same function!

解决方案

只是改变状态,不要return它。

reducers: {
  validate: (state, action) => {
    state.user = action.payload;
  },
}

如果您希望基于 class 的组件订阅您的 redux 存储,那么您仍然可以使用来自 react-redux.

connect 高阶组件

示例:

import { connect } from 'react-redux';
import { validate } from '../path/to/userSlice';

class MyComponent extends Component {

  ...

    // In a function you can simply dispatch the validate action
    // as it was wrapped in a call to dispatch already and injected
    // as a prop.
    this.props.validate(somePayloadValue);

  ...

}

const mapDispatchToProps = {
  validate
};

export default connect(null, mapDispatchToProps)(MyComponent);