所以,我有一个得到分页用户的响应,它看起来像这样。。。
{
data:[{...}, {...}],
links: {first:..., last:...},
meta: {current_page: 1, total: 400, from: 1, to: 10}
}
现在,当使用createEntityAdapter来规范化数据时,我只需要传递";数据";对象数组,而不是整个响应responseData.data
,否则它将无法工作。。。
const usersAdapter: any = createEntityAdapter({});
const initialState = usersAdapter.getInitialState();
export const usersApiSlice = apiSlice.injectEndpoints({
endpoints: builder => ({
getUsers: builder.query<MetadataObj, MetadataObj>({
query: options => ({
url: "/users",
params: options,
}),
transformResponse: (responseData: MetadataObj) => {
return usersAdapter.setAll(initialState, responseData.data);
},
providesTags: (result, error, arg) => {
if (result?.ids) {
return [
{ type: "User", id: "LIST" },
...result.ids.map((id: Number) => ({ type: "User", id })),
];
} else return [{ type: "User", id: "LIST" }];
},
}),
}),
});
export const { useGetUsersQuery } = usersApiSlice;
export const selectUsersResult = usersApiSlice.endpoints.getUsers.select({ page: 1, per_page: 10 });
const selectUsersData = createSelector(selectUsersResult, usersResult => usersResult.data);
export const {
selectAll: selectAllUsers,
selectById: selectUserById,
selectIds: selectUserIds,
} = usersAdapter.getSelectors((state: RootState) => selectUsersData(state) ?? initialState);
现在,我如何获得";元";以及";链接";钥匙?我试着搜索文档,但他们总是假设响应是一个对象数组。
我现在所做的是;usersSlice";在";usersApiSlice";,我像这样把元数据存储在里面。。。
import { createSlice } from '@reduxjs/toolkit';
import { MetadataObj } from '../../../types/globalTypes';
import { RootState } from '../../app/store';
type stateType = {
requestMeta: MetadataObj;
};
const initialState: stateType = {
requestMeta: {},
};
const usersSlice = createSlice({
name: "user",
initialState,
reducers: {
setRequestMeta: (state, action) => {
state.requestMeta = action.payload;
},
},
});
export const { setRequestMeta } = usersSlice.actions;
export const selectRequestMeta = (state: RootState) => state.user.requestMeta;
export default usersSlice.reducer;
然后我在query
函数之后使用transformResponse
函数从原始响应中捕获元并将其存储在usersSlice
中
transformResponse: (responseData: MetadataObj, meta, arg) => {
store.dispatch(setRequestMeta(responseData.meta));
return usersAdapter.setAll(initialState, responseData.data);
}
然而,我有一种感觉,应该有一个更好的方法来处理这个问题。我不确定,但应该有。
任何帮助都是值得的。
下面是一段代码片段,介绍了我是如何让它为我的用例工作的。试着理解这个代码是如何工作的,我相信你会解决你的问题。注意,这是用TypeScript完成的。
import type { EntityId, Dictionary } from "@reduxjs/toolkit";
import { createSelector, createEntityAdapter } from "@reduxjs/toolkit";
import type { IInfo, IPaginatedGetPosts, IPostsForUser } from "../../types";
import { postsApi } from "../api/postsApi";
const postsAdapter = createEntityAdapter({
selectId: post => post.postId,
sortComparer: (a: IPostsForUser, b: IPostsForUser) => b.createdAt.localeCompare(a.createdAt),
});
const initialState = postsAdapter.getInitialState({
info: {
currentPage: 0,
numberOfPosts: 0,
pageSize: 0,
pages: 0,
next: null,
previous: null,
},
});
export const extendedApiSlice = postsApi.injectEndpoints({
endpoints: builder => ({
// we are getting a response of type IPaginatedGetPosts but we are transforming that response when normalizing state
// so this is the new return type of the query
getPosts: builder.query<
{
info: IInfo;
ids: EntityId[];
entities: Dictionary<IPostsForUser>;
},
void
>({
query: () => {
return {
// allow httpOnly cookies to be sent
credentials: "include",
method: "GET",
url: "/get-posts",
};
},
transformResponse: (rawResult: IPaginatedGetPosts) => {
// set initial state to rawResult.postsForUser and also set info from initialState to rawResult.info
return postsAdapter.setAll({ ...initialState, info: rawResult.info }, rawResult.postsForUser);
},
providesTags: result => {
if (result) {
// result is object of entities ids and info
// entities is an object with keys of ids and values of posts
// we need to turn it into an array of posts
return [
...Object.values(result.entities).map(post => ({ type: "Post" as const, postId: post.postId, userId: post.User.userId })),
{ type: "Post", postId: "LIST", userId: "LIST" },
];
}
return [{ type: "Post", postId: "LIST", userId: "LIST" }];
},
}),
}),
});
export const { useGetPostsQuery } = extendedApiSlice;