redux 工具包中的 reducers 和 extrareducers 有什么区别?

kal*_*pts 7 reactjs redux-toolkit

我已经了解了 2 个月的 redux 工具包,并且createSlice有 reducers 和 extrareducers,我知道它们用于从 dispatch 更改状态,但我不知道它们之间的区别,我们应该在哪里使用它们

Ami*_*rji 46

extrareducers实际上就像reducers增强功能一样,但它是为了处理更多选项而构建的,特别是其他操作(例如在其他切片中生成的操作或由createAction或所做的操作createAsyncThunk)。总而言之

您可以在 redux 中调度的所有内容都可以添加到其中。

extrareducers中的属性可以createSlice用作函数对象

该函数形式有一个名为 的输入参数builder

示例 1:该builder.addCase函数从另一个切片添加一个操作(具有 Typescript 类型安全性)。

const {actions,reducer} = createSlice({
  name:'users',
  reducers:{
    ......
  },
  initialState:.... ,
  extraReducers:(builder) => {
    builder.addCase(authActions.logout, state => {
      state.isLoggedIn = false;
    });
  }
});
Run Code Online (Sandbox Code Playgroud)

authActions.logout是另一个切片的另一个动作。

如果您使用createAsyncThunk函数(从“@reduxjs/toolkit”导入)创建一个操作,您可以处理加载、成功和失败状态。

示例 2:处理来自异步 Thunk 的加载状态:

const fetchUserById = createAsyncThunk(
  'users/fetchByIdStatus',
  async (userId, thunkAPI) => {
    const response = await userAPI.fetchById(userId)
    return response.data
  }
)

const {actions,reducer} = createSlice({
  name:'users',
  reducers:{
    ......
  },
  initialState:.... ,
  extraReducers: (builder) => {
    ......
    ......

    builder.addCase(fetchUserById.pending, (state, action) => {
      state.loading=true;
      state.whoseDataIsLoading = action.payload;
    })
  }
});
Run Code Online (Sandbox Code Playgroud)
  1. fetchUserById.pending(处理 asyncThunk 的加载状态)
  2. fetchUserById.rejected(处理失败状态)
  3. fetchUserById.fulfilled(处理成功状态)

构建器还接受addDefaultCase和 ,addMatcher其中addDefaultCase充当传统减速器(没有工具包的 redux 中的减速器)使用的 switch 语句中的默认情况,并且,

addMatcher 与类型谓词函数一起使用,该函数用于推断某些输入具有某种特定类型(此处的操作类型),以确保该操作具有特定类型,然后状态发生变化。

示例 3: 作为extrareducers对象:

const {actions,reducer} = createSlice({
  name:'users',
  reducers:{
    ......
  },
  initialState:.... ,
  extraReducers: {
    ['incrementBy']: (state, action) => {
      state.someValue += action.payload
    }
  }
  });
Run Code Online (Sandbox Code Playgroud)

参考:

  1. https://redux-toolkit.js.org/api/createSlice#extrareducers

  2. https://redux-toolkit.js.org/usage/usage-with-typescript#type-safety-with-extrareducers

  3. https://redux-toolkit.js.org/api/createAsyncThunk

  4. https://redux-toolkit.js.org/usage/usage-with-typescript#typing-builderaddmatcher

  5. https://redux-toolkit.js.org/api/createReducer#builderadddefaultcase


Yil*_*maz 25

假设您有这两个减速器:

const booksSlice = createSlice({
    name: "books",
    initialState: [],
    reducers: {
      addBook(state, action) {
        // this state is not global state. it is only books slice
        state.push(action.payload);
      },
      resetBooks(state, action) {
        // immers assume whatever you return you want your state to be
        return [];
      },
    },});

 export const { addBook, resetBooks } = booksSlice.actions;


  const authorsSlice = createSlice({
    name: "authors",
    initialState: [],
    reducers: {
      addAuthor(state, action) {
        state.push(action.payload);
      },
      resetAuthors(state, action) {
        return [];
      },
    },});

    export const { addAuthor, resetAuthors } =authorsSlice.actions;
Run Code Online (Sandbox Code Playgroud)

两个减速器的初始状态都是[]。假设您在页面中显示“书籍”和“作者”列表,并且您希望有一个按钮来重置这两个状态。

<button onClick={() => handleResetLists()}>
    Clear the page
  </button>
Run Code Online (Sandbox Code Playgroud)

在里面handleResetLists你可以调度这两个动作

const handleReset = () => {
    dispatch(resetBooks());
    dispatch(resetAuthors());
  };
Run Code Online (Sandbox Code Playgroud)

但相反,我可以告诉authorsSlice要注意其他动作类型extraReducers

const authorsSlice = createSlice({
  name: "authors",
  initialState: [],
  reducers: {
    addAuthor(state, action) {
      state.push(action.payload);
    },
    // builder tells this slice to watch for additional action types
    extraReducers(builder) {
      // second argument will update the state
      builder.addCase(booksSlice.actions.reset, () => {
        return [];
      });
    },
  },
});
Run Code Online (Sandbox Code Playgroud)

现在在handleReset函数内部,我将向 BookReducer 发送一个操作,但 AuthorReducer 将监视此操作,并且它也会更新

const handleReset = () => {
    dispatch(resetBooks());
    // I do not need to dispatch this
    // dispatch(resetAuthors()); 
  };
Run Code Online (Sandbox Code Playgroud)

在上面的实现中,authorsSlice是 依赖于booksSlice因为我们使用booksSlice.actions.resetinside extraReducerbookSlice相反,我们创建一个单独的操作,因为如果我们将来摆脱它怎么办

import {createAction} from "@reduxjs/toolkit"
// we are gonna dispatch this
export const resetAction=createAction("lists/reset")
Run Code Online (Sandbox Code Playgroud)

在两个切片器中添加这个 extraReducer:

 extraReducers(builder) {
      builder.addCase(resetAction, (state, action) => {
        state = [];
      });
    },
Run Code Online (Sandbox Code Playgroud)

页面内

 import {resetAction} from "./store/actions"

 const handleReset = () => {
    dispatch(reset());
    // I do not need to dispatch this
    // dispatch(resetAction()); 
  };
Run Code Online (Sandbox Code Playgroud)
  • 请注意,这extraReducer不是由slice.actions


Yuv*_*til 13

如果操作应该由一个减速器处理,请使用reducers

如果操作应该由多个减速器处理,请使用extraReducers


Lin*_*ste 9

reducers属性既创建了一个动作创建器函数,又在切片缩减器中响应该动作。将extraReducers允许你以一个动作回应你的切片减速,但不创建一个动作制作功能。

您将在reducers大部分时间使用。

extraReducers当您处理已在其他地方定义的操作时,您将使用它。最常见的例子是响应一个createAsyncThunk动作和响应另一个切片的动作。