Skip to content

ryfylke-react-as/rtk-query-loader

Repository files navigation

RTK Query Loader

npm npm type definitions npm bundle size

RTK Query Loader lets you create query loaders for your React components.

Made for use with RTK Query, but is also query-agnostic.

Install

yarn add @ryfylke-react/rtk-query-loader
# or
npm i @ryfylke-react/rtk-query-loader

Features

  • Flexible: You can extend and inherit existing loaders to create new ones.
  • Transformable: Combine and transform the data from your loaders to your desired format.
  • Query Agnostic: Can be used with RTK Query, Tanstack Query, JS promises, and more...
  • Configurable: Exposes important configuration options, all of which are inheritable.

You can read more about the features @ the docs.

Example

A simple example of a component using rtk-query-loader:

import {
  createLoader,
  withLoader,
} from "@ryfylke-react/rtk-query-loader";

const loader = createLoader({
  useQueries: () => {
    const pokemon = useGetPokemon();
    const currentUser = useGetCurrentUser();

    return {
      queries: {
        pokemon,
        currentUser,
      },
    };
  },
  onLoading: () => <div>Loading pokemon...</div>,
});

const Pokemon = withLoader((props, loader) => {
  const pokemon = loader.queries.pokemon.data;
  const currentUser = loader.queries.currentUser.data;

  return (
    <div>
      <h2>{pokemon.name}</h2>
      <img src={pokemon.image} />
      <a href={`/users/${currentUser.id}/pokemon`}>
        Your pokemon
      </a>
    </div>
  );
}, loader);

What problem does this solve?

Let's say you have a component that depends on data from more than one query.

function Component(props){
  const userQuery = useGetUser(props.id);
  const postsQuery = userGetPostsByUser(userQuery.data?.id, {
    skip: user?.data?.id === undefined,
  });

  if (userQuery.isError || postsQuery.isError){
    // handle error
  }

  /* possible something like */
  // if (userQuery.isLoading){ return (...) }

  return (
    <div>
      {/* or checking if the type is undefined in the jsx */}
      {(userQuery.isLoading || postsQuery.isLoading) && (...)}
      {userQuery.data && postsQuery.data && (...)}
    </div>
  )
}

The end result is possibly lots of bloated code that has to take into consideration that the values could be undefined, optional chaining, etc...

What if we could instead "join" these queries into one, and then just return early if we are in the initial loading stage. That's basically the approach that rtk-query-loader takes. Some pros include:

  • Way less optional chaining in your components
  • Better type certainty
  • Easy to write re-usable loaders that can be abstracted away from the components