So, I have a response that gets paginated users, and it looks something like this ...
{
data:[{...}, {...}],
links: {first:..., last:...},
meta: {current_page: 1, total: 400, from: 1, to: 10}
}
Now, when using createEntityAdapter to normalize the data, I have to pass just the "data" array of objects to it, not the whole response responseData.data
, otherwise it won't work ...
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);
Now, how do I get the "meta" and "links" keys as well? I tried to search the docs, but they always assumed the response to be an array of objects.
What I did for now is that I created a "usersSlice" beside the "usersApiSlice", and I stored the metadata inside of it like this ...
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;
And then I use the transformResponse
function after the query
function to catch the meta from the original response and store it in the usersSlice
transformResponse: (responseData: MetadataObj, meta, arg) => {
store.dispatch(setRequestMeta(responseData.meta));
return usersAdapter.setAll(initialState, responseData.data);
}
However, I have a feeling that there should be a better way to handle this. I'm not sure, but there should be.
Any help is apprecitated.