Carlos Escobar
Carlos Escobar

Reputation: 434

Question about creating a API with redux-toolkit with react-query

This is more a question rather than an issue. Very new to coding and redux-toolkit I have built an api that fetches from a server a bunch of items. Based on the documentation this should be a simple transaction.

Create the api, get the hook and the hook will provide the properties for you to use in the component. Something like this.

  const {
    data: items, 
    isError,
    isLoading,
    isSuccess,
  } = useGetTravelItemsQuery();

However, based in the documentation and some tutorials online they recommend using createEntityAdapter() to do some sorting with re response. This requires the additional code:

const travelItemsAdapter = createEntityAdapter<travelItem>({
  sortComparer: (a, b) => {
    let x = a.country.toLowerCase();
    let y = b.country.toLowerCase();
    if (x < y) {
      return -1;
    }
    if (x > y) {
      return 1;
    }
    return 0;
  },
});

This requires one to create an initial state so you can generate this with the getInitialState() method. Apart of this, then you have to formalise the state and return it in transformresponse and providesTags so the data is re-fetched if any on the times is invalidated "updating, deleting, etc. Couple of questions.

Doesn't the API state already knows if something changed with the tagTypes you create? I feel that there is a lot of boilerplate here. Also the response then is split in two entities and ids, which I can't figure how I can use this in the component because of typing. See the entire API below:

const baseURL = URL;

export const getItemsReqApi = createApi({
  reducerPath: "getItemsApi",
  baseQuery: fetchBaseQuery({ baseUrl: baseURL }),
  tagTypes: ["travelItems"],
  endpoints: (builder) => ({}),
});
const initialState = travelItemsAdapter.getInitialState();

export const extendedItemsSlice = getItemsReqApi.injectEndpoints({
  endpoints: (builder) => ({
    getTravelItems: builder.query<EntityState<travelItem>, void>({
      query: () => "items.json",
      transformResponse: (rawResults: travelItem[]) => {
        const fetchedItems: travelItem[] = [];
        for (let item in rawResults) {
          fetchedItems.push({
            ...rawResults[item],
            id: item,
          });
        }
        return travelItemsAdapter.setAll(initialState, fetchedItems);
      },
      providesTags: (res) =>
        res?.ids
          ? [
              ...res.ids.map((id) => ({ type: "travelItems" as const, id })),
              { type: "travelItems", id: "travelList" },
            ]
          : [{ type: "travelItems", id: "listTravelItems" }],
    }),
  }),
});

export const selectTravelItemsResponse =
  extendedItemsSlice.endpoints.getTravelItems.select();

export const selectTravelItemsData = createSelector(
  selectTravelItemsResponse,
  (travelItemsResponse) => travelItemsResponse.data
);

export const { useGetTravelItemsQuery } = extendedItemsSlice;

export const { selectAll: selectAllTravelItems } =
  travelItemsAdapter.getSelectors(
    (state: RootState) => selectTravelItemsData(state) ?? initialState
  );

I do see the benefit of using redux-toolkit, but I think I'm going to a rabbit hole because I'm learning so much. Is this above a good practice for dealing with request and API creation.

Upvotes: 1

Views: 1121

Answers (1)

markerikson
markerikson

Reputation: 67449

Hmm. I'm a Redux maintainer, and I think you're over-complicating things :)

I'm assuming you're referring to https://redux.js.org/tutorials/essentials/part-8-rtk-query-advanced#transforming-responses , which I wrote.

RTK Query is a "document cache"-style tool. That means that by default it just saves exactly whatever data the server returned, in exactly that format. If the server response is an array, it saves the array. If the server returned an object, it saves that object.

If you want to transform the data that the server sent into a different structure and save that, yes, you can use transformResponse to do so. It is possible to use createEntityAdapter to turn a received array into a normalized lookup table and cache that normalized value instead.

But, that's entirely optional and not something you need to do all the time. Additionally, the point of that "Essentials" tutorial is to introduce you to many of the different things you can do with Redux Toolkit, but that example is not trying to say you have to always do things that way.

If the server is sending you an array, and all you want to do here is make sure it's sorted, you've got a couple options:

  • Sort that in transformResponse and then return it
  • Do the sorting in the component

Neither of those would require use of createEntityAdapter.

Upvotes: 1

Related Questions