Redux Toolkit:Async Thunk 未正确连接到我的减速器

dea*_*t88 2 redux redux-thunk react-redux redux-toolkit

我试图找出为什么我的异步 thunk 调用没有按预期工作。当我的网站首页加载时,我试图从数据库中提取 JSON 对象数组。现在,API 已被调用,数据已被提取,但动作创建者和切片之间出现了一些问题。我正在尝试console.log action,state但也没有任何结果。

我刚刚学习,redux-toolkit所以对此还很陌生。

这是我的切片:

import { createSlice } from '@reduxjs/toolkit'

const prizesSlice = createSlice({
  name: 'prizes',
  initialState: {
    prizesArray: [],
  },
  reducers: {
    getPrizes(state, action) {
      console.log('hello')
      state.prizes = action.payload
    },
  },
})

export const prizesSliceActions = prizesSlice.actions
export default prizesSlice
Run Code Online (Sandbox Code Playgroud)

这是动作创建者:

import { prizesSliceActions } from './prizes-slice'
import { createAsyncThunk } from '@reduxjs/toolkit'
import * as api from '../apiClient'

// get data
export const fetchPrizeData = createAsyncThunk(
  'prizesArray/getPrizes',

  async () => {
    const data = await api.getAllPrizes()
    console.log(data)
    prizesSliceActions.getPrizes(data)
  }
)
Run Code Online (Sandbox Code Playgroud)

以下是它在组件中的调用方式:

import { fetchPrizeData } from '../store/prizes-actions'
[...]
  useEffect(() => {
    dispatch(fetchPrizeData())
  }, [dispatch])
Run Code Online (Sandbox Code Playgroud)

这是我的商店:

import { configureStore } from '@reduxjs/toolkit'

import prizesSlice from './prizes-slice'

const store = configureStore({
  reducer: { prizes: prizesSlice.reducer },
})

export default store
Run Code Online (Sandbox Code Playgroud)

han*_*ojg 7

好吧,让我试着澄清一下:

主要问题

主要问题是由“case reducer”函数创建的操作对象getPrizes永远不会被分派到实际的 redux 存储。

听起来势不可挡?让我详细解释一下。

这pricesSlice

您如何设置切片存在一个问题。

您将初始状态设置为一个对象,该对象具有一个名为 的属性prizesArray,该属性目前使用一个空数组进行初始化。到目前为止一切都很好。

现在您声明了一个名为 的减速器getPrizes,更具体地说是一个“case 减速器” ,它一次性结合了 reduxaction和。reducer

另外,这很好,但是,命名对我来说有点含糊。这是一个“改变”状态的函数,所以它实际上没有get任何作用,对吧?它真正的作用是setting奖品。所以更合适的名字可能是setPrizes。

好吧,除此之外,现在有一个真正的问题。case 减速器如下所示:

reducers: {
  getPrizes(state, action) {
    console.log('hello')
    state.prizes = action.payload
  },
},
Run Code Online (Sandbox Code Playgroud)

您访问state.prizes,但该字段不存在于该状态!记得在initialState名称中设置为prizesArray。因此,正确的函数应该是这样的:

reducers: {
  setPrizes(state, action) {
    state.prizesArray = action.payload
  },
},
Run Code Online (Sandbox Code Playgroud)

或者在初始状态下重命名该字段,由您决定。

现在我们已经修复了,pricesSlice是时候修复其他部分了。

异步操作 thunk

您创建了一个asyncActionThunk,这很好!但是,您随后调用prizesSlice.actions.getPrizes(data),但从未分派此函数创建的操作对象。

我将您的代码转换为打字稿,因此我们实际上可以看到该操作的返回类型:

返回类型

该函数调用的返回类型只是一个对象。该函数调用只是为您创建一个“redux 操作”对象(或者换句话说,您的减速器函数从未被调用)。现在您需要将该操作对象传递给 redux 以“应用更改”。我们通常dispatch对 redux 进行操作,因此潜在的修复可能如下所示:

export const fetchPrizeData = createAsyncThunk(
  "prizesArray/getPrizes",

  //  - We are getting the thunkApi as second arg.
  // On it, we have the dispatch method available to us
  async (_, thunkApi) => {
    const data = await new Promise((r) => r(["1", "2"]));
    // now we dispatch the action object to the redux store
    // the state gets updated, yei!
    thunkApi.dispatch(prizesSliceActions.setPrizes(data));
  }
);
Run Code Online (Sandbox Code Playgroud)

这已经解决了这个问题,因为我们现在dispatch是 redux 的对象。您可以在文档中阅读有关该thunkAPI参数的更多信息。createAsyncThunk

然而,这并不是使用时的最佳方法createAsyncThunk。我们实际上可以完全利用它。我只是按照文档进行操作:

export const fetchPrizeData = createAsyncThunk("prizes/getPrizes", async () => {
  const data = await api.getAllPrizes()
  console.log(data)
  // We just return our data here
  return data;
});

const prizesSlice = createSlice({
  name: "prizes",
  initialState: {
    prizesArray: []
  },
  reducers: {},
  extraReducers: (builder) => {
    // we setup an extra reducer that will update the state
    // when the async thunk resolved
    builder.addCase(fetchPrizeData.fulfilled, (state, action) => {
      state.prizesArray = action.payload;
    });
  }
});

Run Code Online (Sandbox Code Playgroud)

这种方法使用得createAsyncThunk更加恰当,因此我们还可以获得在商店上调度更清晰的操作的好处。例如,如果我们使用 redux 开发工具检查分派的操作,我们会发现分派的操作prizes/getPrizes/fullfilled是导致状态更新的操作:

redux 调试工具中的 createAsyncThunk 操作

使用另一种方法,我们将在 redux 存储上分派三个操作,并且最好使分派的操作尽可能有意义!

希望这能解决问题,如果还有疑问,请告诉我!