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.

🔬 We're also properly tested! (✓ 30/30)
  • aggregateToQuery
    • ✓ It aggregates query status (167 ms)
  • useCreateQuery
    • ✓ It creates a query (107 ms)
    • ✓ The query can throw error (108 ms)
    • ✓ You can refetch the query (645 ms)
    • ✓ Renders loading state until data is available (130 ms)
    • ✓ Will pass arguments properly (129 ms)
  • withLoader
    • ✓ Renders loading state until data is available (132 ms)
    • ✓ onError renders when applicable (130 ms)
    • ✓ onFetching renders when applicable (319 ms)
    • ✓ Internal state won't reset when using whileFetching (272 ms)
    • ✓ Internal state will reset when using onFetching (271 ms)
    • ✓ Can use custom loader component (129 ms)
    • ✓ loaderComponent is backwards compatible (121 ms)
    • ✓ Can defer some queries (231 ms)
    • ✓ Can defer all queries (130 ms)
    • ✓ Loaders with no queries render immediately (4 ms)
    • ✓ Can remount a component that has a failed query (161 ms)
  • createLoader
    • ✓ Normally, deferred queries do not throw (205 ms)
    • ✓ Deferred queries throw error when configured to (209 ms)
    • ✓ Can send static payload to loader (7 ms)
    • ✓ Loader passes props through queriesArg to queries (128 ms)
    • .extend()
      • ✓ Can extend onLoading (5 ms)
      • ✓ Can extend onError (128 ms)
      • ✓ Can extend onFetching (156 ms)
      • ✓ Can extend whileFetching (133 ms)
      • ✓ Can extend queries (122 ms)
      • ✓ Can extend deferred queries (230 ms)
      • ✓ Can extend many times (282 ms)
      • ✓ Can extend with only transform (133 ms)
      • ✓ Can partially extend config (138 ms)

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