关于处理使用extraReducers报错:createSlice.ts:435 Uncaught Error: The object notation for `createSlice.extraR

前言

今天还是和往常一样按照视频教程学习react,按照步骤来coding的时候,写下了这样一段代码

extraReducers: {
    [fetchHomeMultidataAction.pending](state, action) {
      console.log("fetchHomeMultidataAction pending");
    },
    [fetchHomeMultidataAction.fulfilled](state, action) {
      console.log("fetchHomeMultidataAction fulfilled");
    },
    [fetchHomeMultidataAction.rejected](state, action) {
      console.log("fetchHomeMultidataAction rejected");
    },
  },

然后就出现了报错

image.png

大概意思是说这个api已经废弃了,extraReaducers不再支持对象语法,于是我就去查了下对应的文档,发现确实是RTK更新迭代移除了这个写法。

关于官方给出的更新日志

Object syntax for createSlice.extraReducers and createReducer removed

RTK’s createReducer API was originally designed to accept a lookup table of action type strings to case reducers, like { "ADD_TODO": (state, action) => {} }. We later added the “builder callback” form to allow more flexibility in adding “matchers” and a default handler, and did the same for createSlice.extraReducers.

We have removed the “object” form for both createReducer and createSlice.extraReducers in RTK 2.0, as the builder callback form is effectively the same number of lines of code, and works much better with TypeScript.

As an example, this:

const todoAdded = createAction('todos/todoAdded')

createReducer(initialState, {
  [todoAdded]: (state, action) => {},
})

createSlice({
  name,
  initialState,
  reducers: {
    /* case reducers here */
  },
  extraReducers: {
    [todoAdded]: (state, action) => {},
  },
})

should be migrated to:

createReducer(initialState, (builder) => {
  builder.addCase(todoAdded, (state, action) => {})
})

createSlice({
  name,
  initialState,
  reducers: {
    /* case reducers here */
  },
  extraReducers: (builder) => {
    builder.addCase(todoAdded, (state, action) => {})
  },
})

这里可以看到对象语法被移除,取而代之的是使用builder callback来继续使用extraReducersAPI,此次更新发生v2.0.0版本

image.png

那么什么是extraReducers

extraReducers 是 Redux Toolkit 提供的一个方法,用于在 createSlice 中定义额外的 reducer。它允许一个切片 reducer 响应和更新自己的状态,以及对其他部分定义的 action 类型进行处理。

为什么会有 extraReducers 方法呢?这是因为在一个复杂的应用中,不同的切片 reducer 可能需要相互协作,响应相同的 action 类型。除了处理自己生成的 action 类型外,切片 reducer 有时还需要对其他切片或模块生成的 action 类型进行响应。

extraReducers 提供了一种解决这个问题的机制。它允许在 createSlice 中定义额外的 case reducer,以响应其他切片、模块或应用中定义的 action 类型。这样,一个切片 reducer 可以独立地响应多个不同的 action 类型,并更新自己的状态。

extraReducers 的特点如下:

  1. 灵活性:extraReducers 允许您根据需要定义任意数量的额外 case reducer。这使得切片 reducer 可以适应多样化的应用场景,处理不同的 action 类型和逻辑。
  2. 协作性:通过 extraReducers,不同的切片 reducer 可以独立地响应相同的 action 类型,并根据自己的需要更新状态。这种协作性使得不同的切片可以共同构建和维护应用的整体状态。
  3. Immer 支持:与 reducers 字段类似,extraReducers 中的每个 case reducer 都被包装在 Immer 中。这意味着您可以使用方便的 “mutating” 语法来安全地更新状态,而无需手动编写不可变更新逻辑。
  4. TypeScript 支持:extraReducers 充分利用了 TypeScript 的类型推断功能。使用 “builder callback” 形式,它可以根据提供的 action creator 推断出准确的 action 类型,并提供类型检查和自动完成的支持。

总的来说,extraReducers 是 Redux Toolkit 提供的一个强大工具,用于定义切片 reducer 响应和更新自己的状态,以及处理其他部分定义的 action 类型。它提供了灵活性、协作性和 TypeScript 支持,使得编写和维护复杂的 Redux 应用变得更加简单和可靠。

这意味这在传统的reducers中无法完成的异步操作,可以在extraReducers中实现,来实现不同异步请求的状态管理。

使用extraReducers完成异步操作

const incrementBy = createAction('incrementBy')  
const decrement = createAction('decrement')  
  
function isRejectedAction(action) {  
return action.type.endsWith('rejected')  
}  
  
createSlice({  
name: 'counter',  
initialState: 0,  
reducers: {},  
extraReducers: (builder) => {  
builder  
.addCase(incrementBy, (state, action) => {  
// action is inferred correctly here if using TS  
})  
// You can chain calls, or have separate `builder.addCase()` lines each time  
.addCase(decrement, (state, action) => {})  
// You can match a range of action types  
.addMatcher(  
isRejectedAction,  
// `action` will be inferred as a RejectedAction due to isRejectedAction being defined as a type guard  
(state, action) => {}  
)  
// and provide a default case if no other handlers matched  
.addDefaultCase((state, action) => {})  
},  
})

以上就是官方给出的使用extraReducers的示例代码,我们将分为两步将完成本次数据请求的异步操作。

1. 使用createAsyncThunk创建异步请求函数

export const fetchHomeMultidataAction = createAsyncThunk(
  "fetch/homeMultidata",
  async () => {
    const res = await axios.get("http://123.207.32.32:8000/home/multidata");

    return res.data;
  }
);

createAsyncThunk 通过生成的 thunk action 处理异步操作的各个阶段,包括开始、成功和失败。下面是 createAsyncThunk 如何处理这些阶段的说明:

  1. 开始(Pending)阶段:

    • 当生成的 thunk action 被分发时,它会立即触发开始阶段。
    • 开始阶段的 action 类型是由 createAsyncThunk 接收的第一个参数中定义的。
    • 开始阶段的 action 会传递给 extraReducers 中对应的 case reducer 进行处理。
  2. 成功(Fulfilled)阶段:

    • 在异步操作成功完成后,createAsyncThunk 会自动分发一个成功的 action。
    • 成功阶段的 action 类型是由 createAsyncThunk 接收的第一个参数中定义的,并附加了 _fulfilled 后缀。
    • 成功阶段的 action 会携带异步操作的结果数据,可以通过 action.payload 进行访问。
    • 成功阶段的 action 会传递给 extraReducers 中对应的 case reducer 进行处理。
  3. 失败(Rejected)阶段:

    • 在异步操作失败时,createAsyncThunk 会自动分发一个失败的 action。
    • 失败阶段的 action 类型是由 createAsyncThunk 接收的第一个参数中定义的,并附加了 _rejected 后缀。
    • 失败阶段的 action 会携带关于失败的错误信息,可以通过 action.error 或 action.payload 进行访问。
    • 失败阶段的 action 会传递给 extraReducers 中对应的 case reducer 进行处理。

在 extraReducers 中,可以定义相应的 case reducer 来处理这些阶段的 action。根据 action 的类型,您可以更新状态、标记加载状态、存储数据等等。这样,就可以轻松地在 Redux 中管理和反应异步操作的状态。

2. 在extraReducers中管理这些阶段的action

extraReducers: (builder) => {
    builder
      .addCase(fetchHomeMultidataAction.pending, (state, action) => {
        console.log("fetchHomeMultidataAction pending");
      })
      .addCase(fetchHomeMultidataAction.fulfilled, (state, { payload }) => {
        console.log("fetchHomeMultidataAction fulfilled", payload);
        state.banners = payload.data.banner.list;
        state.recommends = payload.data.recommend.list;
      })
      .addCase(fetchHomeMultidataAction.rejected, (state, action) => {
        console.log("fetchHomeMultidataAction rejected");
      });
  },

builder 是一个在 Redux Toolkit 中用于定义 reducer 和处理异步操作的工具对象。它是由 createReducer 和 extraReducers 提供的回调函数中的第一个参数。

在 Redux Toolkit 中,builder 对象具有一组方法,用于定义 reducer 的不同情况(cases)和相应的处理逻辑。这些方法包括 addCaseaddMatcheraddDefaultCase 等。

在上述代码中,我们使用了 builder 对象的 addCase 方法来定义不同的 action 状态以及相应的处理函数。例如,fetchTodo.pending 表示处理 fetchTodo 异步 action 的 pending(进行中)状态,而 fetchTodo.fulfilled 表示处理 fulfilled(已完成)状态,fetchTodo.rejected 表示处理 rejected(已拒绝)状态。

通过使用 builder 对象,可以更简洁地定义 reducer 的逻辑,而无需显式地编写 switch-case 语句。它提供了一种更直观和易于使用的方式来处理 reducer 中的不同情况。

效果图

image.png

至此我们就完成了用builder语法在extraReducers中完成异步请求获取网络数据

为什么移除对象语法

此次更改有几个方面的好处:

  1. 一致性:移除对象形式,使 createReducercreateSlice.extraReducers 使用相同的 “builder callback” 形式,以保持一致性和统一性。这样,开发人员在编写代码时无需在两种不同的语法之间切换,提高了代码的可读性和可维护性。

  2. 可扩展性:使用 “builder callback” 形式,可以更灵活地扩展和组织 reducer 的逻辑。可以轻松地添加额外的匹配逻辑、处理默认情况,或者使用其他高级特性,比如使用条件语句、循环等。这种灵活性使得编写复杂的逻辑变得更加简单和清晰。

  3. TypeScript 支持: “builder callback” 形式更适合与 TypeScript 结合使用。它可以从提供的 action creator 推断出准确的 action 类型,并提供更好的类型检查和自动完成。这有助于减少潜在的类型错误,并提升代码的可靠性和可维护性。

总的来说,通过移除对象形式,Redux Toolkit 提供了一种更一致、更灵活和更好与 TypeScript 配合的方式来定义 reducers。这种改进使得编写和维护 Redux 相关的代码更加简单、清晰和可靠。

小结

前端的生命力在于其持续的技术革新和变革。作为一个前端开发者,我们必须时刻保持学习的态度,以跟随技术的快速演进和不断涌现的新语言、新框架和新工具。

  • 27
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值