我正在使用 redux 工具包。
我有不同的切片,它们有自己的状态。
我有一个角色
import { createSlice } from '@reduxjs/toolkit';
import { getAllRoles } from './roleActions';
const initialState = {
roles: [],
loading: false,
isSuccess: false,
message: '',
};
const authReducer = createSlice({
name: 'roles',
initialState,
reducers: {},
extraReducers: (builder) => {
builder
.addCase(getAllRoles.pending, (state) => {
state.isSuccess = false;
state.message = '';
state.loading = true;
})
.addCase(getAllRoles.fulfilled, (state, { payload }) => {
state.roles = payload.data;
state.message = payload.message;
state.isSuccess = true;
state.loading = false;
})
.addCase(getAllRoles.rejected, (state, { payload }) => {
state.isSuccess = false;
state.message = payload;
state.loading = false;
});
},
});
export default authReducer.reducer;
这是 getAllRoles 操作
import { createAsyncThunk } from '@reduxjs/toolkit';
import API from '../../api';
import { formatError } from '@utils/index';
export const getAllRoles = createAsyncThunk('role/getAllRoles', async (_, { rejectWithValue }) => {
try {
const { data } = await API.get('/roles');
return data;
} catch (error) {
return rejectWithValue(formatError(error));
}
});
我将所有角色获取为:
useEffect(() => {
dispatch(getAllRoles());
}, [dispatch]);
另一片:
import { createSlice } from '@reduxjs/toolkit';
import { deleteJob, getJobs, updateJob, createJob } from './jobActions';
const initialValues = {
data: {
jobs: [],
totalCount: 0,
},
loading: false,
isSuccess: false,
message: '',
};
const jobsReducer = createSlice({
name: 'jobs',
initialState: initialValues,
reducers: {},
extraReducers: (builder) => {
// Get Jobs
builder
.addCase(getJobs.fulfilled, (state, { payload }) => {
return {
...state,
data: payload.data,
message: payload.message,
isSuccess: true,
loading: false,
};
})
.addCase(deleteJob.fulfilled, (state, { payload }) => {
const updatedJobs = [...state.data.jobs.filter((job) => job._id !== payload)];
return {
...state,
data: {
totalCount: state.data.totalCount - 1,
jobs: updatedJobs,
},
message: 'Job deleted successfully',
isSuccess: true,
loading: false,
};
})
.addCase(updateJob.fulfilled, (state, { payload }) => {
const updatedJobs = [...state.data.jobs.filter((job) => job._id !== payload.data._id), payload.data];
return {
...state,
data: {
totalCount: state.data.totalCount,
jobs: updatedJobs,
},
message: payload.message,
isSuccess: true,
loading: false,
};
})
.addCase(createJob.fulfilled, (state, { payload }) => {
return {
...state,
data: {
totalCount: state.data.totalCount + 1,
jobs: [payload.data, ...state.data.jobs],
},
message: payload.message,
isSuccess: true,
loading: false,
};
})
.addMatcher(
(action) => action.type.endsWith('/pending'),
(state) => ({
...state,
isSuccess: false,
message: '',
loading: true,
}),
)
.addMatcher(
(action) => action.type.endsWith('/rejected'),
(state, { payload }) => ({
...state,
isSuccess: false,
message: payload,
loading: false,
}),
);
},
});
export default jobsReducer.reducer;
再来一片:
import { createUser, deleteUser, getUsers, updateUser } from './userActions';
const initialState = {
users: [],
loading: false,
isSuccess: false,
message: '',
};
const usersReducer = createSlice({
name: 'users',
initialState,
reducers: {},
extraReducers: (builder) => {
// Get Users
builder.addCase(getUsers.fulfilled, (state, { payload }) => {
state.loading = false;
state.message = payload.message;
state.users = payload.data;
state.isSuccess = true;
});
// Delete Users
builder.addCase(deleteUser.fulfilled, (state, { payload }) => {
state.loading = false;
state.message = payload.message;
state.users = [...state.users.filter((user) => user._id !== payload)];
state.isSuccess = true;
});
// Update User
builder.addCase(updateUser.fulfilled, (state, { payload }) => {
state.loading = false;
state.message = payload.message;
state.users.splice(
state.users.findIndex((user) => user.email === payload.data.email),
1,
payload.data,
);
state.isSuccess = true;
state.message = payload.message;
});
// Create User
builder.addCase(createUser.fulfilled, (state, { payload }) => {
state.loading = false;
state.message = payload.message;
state.users.unshift(payload.data);
state.isSuccess = true;
});
// Pending State
builder.addMatcher(
(action) => action.type.endsWith('/pending'),
(state) => {
state.isSuccess = false;
state.message = '';
state.loading = true;
},
);
// Rejected State
builder.addMatcher(
(action) => action.type.endsWith('/rejected'),
(state, { payload }) => {
state.isSuccess = false;
state.message = payload;
state.loading = false;
},
);
},
});
export default usersReducer.reducer;
现在的问题是,当 getAllRoles 触发时,它应该将其加载状态更改为 true 以确保其正确执行,
但它也会将用户和作业的加载状态更改为 true,仅更改加载状态,并且不会设置回 false。
就像我有其他一些切片一样,它们也有这样的行为,
当我调度 getJobs 的操作时
现在它还有不同的行为,例如它将用户的加载状态更改为 true,但不更改角色或任何其他的加载状态。
这是 redux devtools 截图:
我选择了 Roles/getAllRoles/pending 操作,并检查状态差异,它正在更改其他切片的加载状态,但它也不应该这样做。
这是我的商店配置:
import storage from 'redux-persist/lib/storage';
import { combineReducers } from 'redux';
import { persistReducer } from 'redux-persist';
import thunk from 'redux-thunk';
import { authReducer, usersReducer, rolesReducer, jobsReducer, surveysReducer, pageInfoReducer } from './features';
const reducers = combineReducers({
auth: authReducer,
users: usersReducer,
roles: rolesReducer,
jobs: jobsReducer,
survey: surveysReducer,
pageInfo: pageInfoReducer,
});
const store = configureStore({
reducer: reducers,
devTools: process.env.NODE_ENV !== 'production',
middleware: [thunk],
});
export default store;
尝试删除addMatcher,使用动作和切片的唯一名称,尝试单独使用builder.addCase而不是改变方式。没有任何效果。
作业和用户状态切片都定义了处理任何待处理或拒绝的操作的减速器案例。
const jobsReducer = createSlice({
name: 'jobs',
initialState: initialValues,
reducers: {},
extraReducers: (builder) => {
// Get Jobs
builder
...
.addMatcher(
(action) => action.type.endsWith('/pending'), // <-- any pending
(state) => ({
...state,
isSuccess: false,
message: '',
loading: true,
}),
)
.addMatcher(
(action) => action.type.endsWith('/rejected'), // <-- any rejected
(state, { payload }) => ({
...state,
isSuccess: false,
message: payload,
loading: false,
}),
);
},
});
const usersReducer = createSlice({
name: 'users',
initialState,
reducers: {},
extraReducers: (builder) => {
...
// Pending State
builder.addMatcher(
(action) => action.type.endsWith('/pending'), // <-- any pending
(state) => {
state.isSuccess = false;
state.message = '';
state.loading = true;
},
);
// Rejected State
builder.addMatcher(
(action) => action.type.endsWith('/rejected'), // <-- any rejected
(state, { payload }) => {
state.isSuccess = false;
state.message = payload;
state.loading = false;
},
);
},
});
当
'role/getAllRoles/pending'
被分派到存储时,这些其他减速器案例将使用当前代码正确更新和设置其本地 loading
状态(以及其案例中的状态更新)。如果异步 getAllRoles
操作成功完成,则在这些其他状态片中不存在清除其加载状态的情况。
回想一下,Redux 存储的减速器树中的所有减速器都会传递分派到存储的每个操作,并且只有具有特定操作案例的减速器才会响应。
我怀疑您对作业切片情况下仅、
deleteJob
、getJobs
、updateJob
和createJob
操作的待处理/拒绝状态感兴趣,并且仅在用户切片的情况下,createUser
、deleteUser
、getUsers
和updateUser
的待处理/拒绝状态。为此,我建议使用 isPending
、isFulfilled
和 isRejected
匹配实用程序。
示例:
import { createSlice, isPending, isFulfilled, isRejected } from '@reduxjs/toolkit';
import { deleteJob, getJobs, updateJob, createJob } from './jobActions';
const initialState = {
data: {
jobs: [],
totalCount: 0,
},
loading: false,
isSuccess: false,
message: '',
};
const jobsReducer = createSlice({
name: 'jobs',
initialState,
extraReducers: (builder) => {
// Get Jobs
builder
.addCase(getJobs.fulfilled, (state, { payload }) => {
return {
...state,
data: payload.data,
message: payload.message,
};
})
.addCase(deleteJob.fulfilled, (state, { payload }) => {
const updatedJobs = state.data.jobs.filter((job) => job._id !== payload);
return {
...state,
data: {
totalCount: state.data.totalCount - 1,
jobs: updatedJobs,
},
message: 'Job deleted successfully',
};
})
.addCase(updateJob.fulfilled, (state, { payload }) => {
return {
...state,
data: {
totalCount: state.data.totalCount,
jobs: state.data.jobs
.filter((job) => job._id !== payload.data._id)
.concat(payload.data),
},
message: payload.message,
};
})
.addCase(createJob.fulfilled, (state, { payload }) => {
return {
...state,
data: {
totalCount: state.data.totalCount + 1,
jobs: [payload.data, ...state.data.jobs],
},
message: payload.message,
};
})
.addMatcher(
isPending(deleteJob, getJobs, updateJob, createJob),
(state) => {
state.isSuccess: false,
state.message: '',
state.loading: true,
},
)
.addMatcher(
isFulfilled(deleteJob, getJobs, updateJob, createJob),
(state) => {
state.isSuccess: true,
state.loading: false,
},
)
.addMatcher(
isRejected(deleteJob, getJobs, updateJob, createJob),
(state, { payload }) => {
state.isSuccess: false,
state.message: payload,
state.loading: false,
},
);
},
});
import { createSlice, isPending, isFulfilled, isRejected } from '@reduxjs/toolkit';
import { createUser, deleteUser, getUsers, updateUser } from './userActions';
const initialState = {
users: [],
loading: false,
isSuccess: false,
message: '',
};
const usersReducer = createSlice({
name: 'users',
initialState,
extraReducers: (builder) => {
// Get Users
builder.addCase(getUsers.fulfilled, (state, { payload }) => {
state.message = payload.message;
state.users = payload.data;
});
// Delete Users
builder.addCase(deleteUser.fulfilled, (state, { payload }) => {
state.message = payload.message;
state.users = [...state.users.filter((user) => user._id !== payload)];
});
// Update User
builder.addCase(updateUser.fulfilled, (state, { payload }) => {
state.message = payload.message;
state.users.splice(
state.users.findIndex((user) => user.email === payload.data.email),
1,
payload.data,
);
});
// Create User
builder.addCase(createUser.fulfilled, (state, { payload }) => {
state.message = payload.message;
state.users.unshift(payload.data);
});
// Pending State
builder.addMatcher(
isPending(createUser, deleteUser, getUsers, updateUser),
(state) => {
state.isSuccess = false;
state.message = '';
state.loading = true;
},
);
// Fulfilled State
builder.addMatcher(
isFulfilled(createUser, deleteUser, getUsers, updateUser),
(state) => {
state.isSuccess = true;
state.message = '';
state.loading = false;
},
);
// Rejected State
builder.addMatcher(
isRejected(createUser, deleteUser, getUsers, updateUser),
(state, { payload }) => {
state.isSuccess = false;
state.message = payload;
state.loading = false;
},
);
},
});