All files / app/features/userQueries useUsers.ts

100% Statements 39/39
100% Branches 10/10
100% Functions 15/15
100% Lines 36/36

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 819x 9x   9x 9x 9x 9x   20x       429x 429x 429x 92x 5x   18x         429x 90x       429x 429x 2x 2x       429x   468x 465x 67x           429x 465x 465x 457x 457x       435x 429x   429x   322x   429x                   409x 409x 409x                
import { userKey } from "features/queryKeys";
import { userStaleTime } from "features/userQueries/constants";
import { User } from "proto/api_pb";
import { useCallback, useEffect, useRef } from "react";
import { useQueries, useQueryClient } from "react-query";
import { service } from "service";
import { arrayEq } from "utils/arrayEq";
 
export default function useUsers(
  ids: (number | undefined)[],
  invalidate = false,
) {
  const queryClient = useQueryClient();
  const idsRef = useRef(ids);
  const handleInvalidation = useCallback(() => {
    if (invalidate) {
      queryClient.invalidateQueries({
        predicate: (query) =>
          query.queryKey[0] === userKey() &&
          !!idsRef.current.includes(query.queryKey[1] as number),
      });
    }
  }, [invalidate, queryClient]);
  useEffect(() => {
    handleInvalidation();
  }, [handleInvalidation]);
 
  //arrays use reference equality, so you can't use ids in useEffect directly
  useEffect(() => {
    if (!arrayEq(idsRef.current, ids)) {
      idsRef.current = ids;
      handleInvalidation();
    }
  });
 
  const queries = useQueries<User.AsObject, Error>(
    ids
      .filter((id): id is number => !!id)
      .map((id) => ({
        queryFn: () => service.user.getUser(id.toString()),
        queryKey: userKey(id),
        staleTime: userStaleTime,
      })),
  );
 
  const errors = queries
    .map((query) => query.error?.message)
    .filter((e): e is string => typeof e === "string");
  const isLoading = queries.some((query) => query.isLoading);
  const isFetching = queries.some((query) => query.isFetching);
 
  // If at least one user query is not loading (i.e. has data loaded before), whilst
  // some other (likely new) queries are fetching, then it's a refetch
  const isRefetching = !queries.every((query) => query.isLoading) && isFetching;
  const isError = !!errors.length;
 
  const usersById = isLoading
    ? undefined
    : new Map(queries.map((q, index) => [ids[index], q.data]));
 
  return {
    data: usersById,
    errors,
    isError,
    isFetching,
    isLoading,
    isRefetching,
  };
}
 
export function useUser(id: number | undefined, invalidate = false) {
  const result = useUsers([id], invalidate);
  return {
    data: result.data?.get(id),
    error: result.errors.join("\n"),
    isError: result.isError,
    isFetching: result.isFetching,
    isLoading: result.isLoading,
  };
}