在 prepare 回调函数中使用状态属性 (Redux Toolkit)。

huangapple go评论62阅读模式
英文:

Use a state property inside the prepare callback (Redux Toolkit)

问题

I have a store with this initialState:

const initialState = {
 todos : [] // [{ task: "todo something", description: "have todo something" },  ...] 
 maxTodos: 5
 ....
}

I want inside the prepare callback to id new todo that I will add, based on the length of the current todos array.

reducers: {
  addTodo: {
    reducer: (state, action) => {
      return { ...state, todos: [...state.todos, action.payload]}
    },
    prepare: (state, text) => {
      const id = state.todos?.length; // the error is some what here
      return { payload: { id, text } }
    },
  },
....

Is there a way to access state inside the prepare callback to the slice state?

Or a different approach that can solve this?


The easy solution to send from the dispatch the length of the todo's or the create a nanoId() inside the prepare.

For now I don't want to implement this approach (written above), I want to send via the dispatch only the new todo that I want to add, and the id will be transparent to the dispatch because I want to control the todo's via their position in the array.

英文:

I have a store with this initialState:

const initialState = {
 todos : [] // [{ task: "todo something", description: "have todo something" },  ...] 
 maxTodos: 5
 ....
}

I want inside the prepare callback to id new todo that I will add, based on the length of the current todos array.

reducers: {
  addTodo: {
    reducer: (state, action) => {
      return { ...state, todos: [...state.todos, action.payload]}
    },
    prepare: (state, text) => {
      const id = state.todos?.length; // the error is some what here
      return { payload: { id, text } }
    },
  },
....

Is there a way to access state inside the prepare callback to the slice state?

Or a different approach that can solve this?


The easy solution to send from the dispatch the length of the todo's or the create a nanoId() inside the prepare.

For now I don't want to implement this approach (written above), I want to send via the dispatch only the new todo that I want to add, and the id will be transparent to the dispatch because I want to control the todo's via their position in the array.

答案1

得分: 3

prepare函数用于在reducer函数接收操作对象之前对其进行预处理。这是编写操作创建者的一种方式,可以接受不止一个参数,或者向操作对象添加元数据。

在这里,我看不出添加一个id属性的用例,该属性的值是状态中数组的长度,这是因为prepare函数无法访问状态对象。我的建议是在reducer函数中计算id,因为在那里状态是可访问的。

示例:

reducers: {
  addTodo: (state, action) => {
    state.todos.push({
      text: action.payload,
      id: state.todos.length,
    })
  },
...

这可能有点愚蠢,但如果您真的只是想要一个操作创建者,返回一个带有text和基于当前状态生成的id属性的payload,您可以使用createAsyncThunk并从ThunkAPI中访问getState

示例:

const addTodo = createAsyncThunk(
  "todos/addTodo",
  (text, { getState }) => ({
    text,
    id: getState().todos.length, // *
  })
);

const todosSlice = createSlice({
  name: "todos",
  initialState,
  reducers: {
    ...
  },
  extraReducers: builder => {
    builder.addCase(addTodo.fulfilled, (state, action) => {
      state.todos.push(action.payload);
    });
  },
});

**注意:**根据reducers如何组合以形成传递给存储配置器的根reducer,可能需要编辑以选择正确的状态。

英文:

The prepare function is used to preprocess the action object prior to the reducer function receiving it. It's a way to write action creators that take more than a single argument, or to add meta data to the action object.

I don't see much of a use case here for adding an id property that is the length of the array in state from the prepare function. The prepare function just doesn't have access to the state object. My suggestion would be to just compute the id in the reducer function where the state is accessible.

Example:

reducers: {
  addTodo: (state, action) => {
    state.todos.push({
      text: action.payload,
      id: state.todos.length,
    })
  },
...

This would possibly be a bit silly, but if you really just wanted an action creator that returned a payload with the text and a generated id property based on the current state you could use createAsyncThunk and access getState from the ThunkAPI.

Example:

const addTodo = createAsyncThunk(
  "todos/addTodo",
  (text, { getState }) => ({
    text,
    id: getState().todos.length, // *
  })
);

const todosSlice = createSlice({
  name: "todos",
  initialState,
  reducers: {
    ...
  },
  extraReducers: builder => {
    builder.addCase(addTodo.fulfilled, (state, action) => {
      state.todos.push(action.payload);
    });
  },
});

*Note: Edit to select correct state based on how the reducers are combined to form the root reducer passed to the store configurator.

huangapple
  • 本文由 发表于 2023年3月9日 17:30:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/75682681.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定