redux工具箱中的减速器和超减速器之间的区别是什么



我已经学习redux工具包两个月了,在createSlice中有reducersextrareducers,我知道它们用于从调度更改状态,但我不知道区别,我们应该在哪里使用它们?

reducers属性既创建了一个动作创建者函数,又响应切片缩减器中的该动作。extraReducers允许您响应切片缩减器中的动作,但不创建动作创建者函数。

您将在大多数时间使用reducers

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

extrareducers实际上与具有增强功能的reducers类似,但它的构建是为了处理更多选项,尤其是其他操作(如其他切片中生成的选项或createActioncreateAsyncThunk执行的操作)。总之

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

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

函数表单有一个名为builder的输入参数。

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

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

这里的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;
})
}
});
  1. fetchUserById.pending(处理asyncThunk的加载状态)
  2. fetchUserById.rejected(处理失败状态)
  3. fetchUserById已完成(处理成功状态)

构造器还接受addDefaultCaseaddMatcher,其中addDefaultCase充当传统减速器(不带工具箱的redux中的减速器)和使用的切换语句中的默认情况

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

示例3:作为对象的extrareducers

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

参考文献:

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

  2. https://redux-toolkit.js.org/usage/usage-with-typescript#type-带减速器的安全性

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

  4. https://redux-toolkit.js.org/usage/usage-with-typescript#typing-楼宇地址匹配器

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

假设您有这两个减速器:

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;

两个减速器的初始状态均为[]。假设您显示";书籍";以及";作者";列表,并且您希望有一个按钮来重置这两种状态。

<button onClick={() => handleResetLists()}>
Clear the page
</button>

handleResetLists中,您可以调度两个动作

const handleReset = () => {
dispatch(resetBooks());
dispatch(resetAuthors());
};

但是,我可以告诉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 [];
});
},
},
});

现在在handleReset函数中,我将向图书减速器发送一个操作,但作者减速器将关注这个操作,它也将更新

const handleReset = () => {
dispatch(resetBooks());
// I do not need to dispatch this
// dispatch(resetAuthors()); 
};

在上面的实现中,authorsSlice依赖于booksSlice,因为我们在extraReducer中使用booksSlice.actions.reset。相反,我们创建了一个单独的操作,因为如果我们在未来的中去掉bookSlice会怎么样

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

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

extraReducers(builder) {
builder.addCase(resetAction, (state, action) => {
state = [];
});
},

页面内

import {resetAction} from "./store/actions"
const handleReset = () => {
dispatch(reset());
// I do not need to dispatch this
// dispatch(resetAction()); 
};
  • 请注意,extraReducer不是由slice.actions生成的操作的一部分

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

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

假设您有一个TodoReducer.js文件,其中有manageTodo reducer:

import {createSlice} from '@reduxjs/toolkit';
const initialState = {
todo: [],
};
export const manageToDo = createSlice({
name: 'Todo',
initialState: initialState,
reducers: {
add: (state, action) => {
console.log(action);
state.todo = [...state.todo, action.payload];
},
del: (state, action) => {
state.todo.splice(action.payload, 1);
},
edit: (state, action) => {
state.todo.splice(action.payload.index, 1, action.payload.item);
},
clearTodo: state => {
state.todo = [];
},
},
});

你想要的,在加todo时,counter&删除todo时,计数器会递减这样你就可以像这样使用extraReducer

CounterReducer.js

import {createSlice} from '@reduxjs/toolkit';
import {manageToDo} from './TodoReducer';
const counterInitialState = {
counter: 0,
};
const manageCounter = createSlice({
name: 'Counter',
initialState: counterInitialState,
reducers: {
increment: (state, action) => {
console.log('testing increment', state.counter);
state.counter++;
},
decrement: (state, action) => {
state.counter--;
},
},
extraReducers: builder => {
builder.addCase(manageToDo.actions.clearTodo, () => {
return 0;
});
builder.addCase(manageToDo.actions.add, state => {
state.counter++;
});
builder.addCase(manageToDo.actions.del, state => {
state.counter--;
});
},
});
export const manageCounterReducer = manageCounter.reducer;
export const {increment, decrement} = manageCounter.actions;

ExtraReducer是reducer,它的作用是做reducer。我在createAsyncThunk()中学习并使用了它。(额外)减速器的作用是具有两个参数的纯函数——实际状态和动作。减速器是减速器的一个切片,而extraReducer是减速器、待处理、已归档和已拒绝的三个切片。每一片(额外的)减速器都是动作的创造者
每个动作创建者都被分派到存储区
Thunk是中间件模式中的函数。Thunk是一个动作创造者,它创造了另外三个动作创造者:未决、完整和拒绝。这三个动作的创造者是三个不变地更新状态的多余的reducer。更多信息:https://www.youtube.com/watch?v=2M-HR2J88S4

相关内容

  • 没有找到相关文章

最新更新