Daniel Corona
Daniel Corona

Reputation: 1222

Type error with react-query and UseQueryResult

I am using react-query in my TS project:

useOrderItemsForCardsInList.ts:

import { getToken } from '../../tokens/getToken';
import { basePath } from '../../config/basePath';
import { getTokenAuthHeaders } from '../../functions/sharedHeaders';
import { useQuery } from 'react-query';

async function getOrderItemsForCardsInList(listID: string) {
    const token = await getToken();
    const response = await fetch(`${basePath}/lists/${listID}/order_items/`, {
        method: 'GET',
        headers: getTokenAuthHeaders(token)
    });

    return response.json();
}

export default function useOrderItemsForCardsInList(listID: string) {
    if (listID != null) {
        return useQuery(['list', listID], () => {
            return getOrderItemsForCardsInList(listID);
        });
    }
}

I use my query result over here:

import { useCardsForList } from '../../hooks/Cards/useCardsForList';
import useOrderItemsForCardsInList from '../../hooks/Lists/useOrderItemsForCardsInList';
import usePaginateCardsInList from '../../hooks/Cards/usePaginateCardsInList';

export default function CardsListFetch({ listID }: { listID: string }) {
    const { isLoading, isError, error, data } = useCardsForList(listID);
    const { orderItems } = useOrderItemsForCardsInList(listID);
    const pagesArray = usePaginateCardsInList(orderItems, data);

    return (
        ...
    );
}

However, on my const { orderItems } = useOrderItemsForCardsInList(listID); line, I get the following error:

Property 'orderItems' does not exist on type 'UseQueryResult<any, unknown> | undefined'.

How can I resolve this? I don't really know how to consume the result of my query on Typescript, any help is be appreciated

Upvotes: 1

Views: 12681

Answers (2)

Eugenijus S.
Eugenijus S.

Reputation: 384

If you are using React with react-query, I suggest you install this devDependency called: "@types/react-query". When using VS Code or any other smart text editor that will help, because it will help you with type suggestions.

npm i --save-dev @types/react-query

Then go to your code and fix couple things:

  • remove condition from useOrderItemsForCardsInList(). Don’t call React Hooks inside loops, conditions, or nested functions. See React hooks rules.
  • import UseCategoryResult and define interface for your return object. You can call it OrderItemsResult or similar. Add type OrderType with the fields of the order object or just use orderItems: any for now.
  • Add return type UseQueryResult<OrderItemsResult> to useOrderItemsForCardsInList() function.
  • Fix return value of getOrderItemsForCardsInList(), it should not be response.json() because that would be Promise, not actual data. Instead use await response.json().
  • So your function useOrderItemsForCardsInList() will return UseQueryResult which has properties like isLoading, error and data. In your second code snipper, you already use data in one place, so instead rename data to orderData and make sure you define default orderItems to empty array to avoid issues: data: orderData = {orderItems: []}

useOrderItemsForCardsInList.ts:

import { getToken } from '../../tokens/getToken';
import { basePath } from '../../config/basePath';
import { getTokenAuthHeaders } from '../../functions/sharedHeaders';
import { useQuery, UseCategoryResult } from 'react-query';

type OrderType = {
    id: string;
    name: string;
    // whatever fields you have.
}

interface OrderItemsResult {
  orderItems: OrderType[],
}

async function getOrderItemsForCardsInList(listID: string) {
    const token = await getToken();
    const response = await fetch(`${basePath}/lists/${listID}/order_items/`, {
        method: 'GET',
        headers: getTokenAuthHeaders(token)
    });
    const data = await response.json();
    return data;
}

export default function useOrderItemsForCardsInList(listID: string): UseQueryResult<OrderItemsResult> {
    return useQuery(['list', listID], () => {
        return getOrderItemsForCardsInList(listID);
    });
}

Use your query result:

import { useCardsForList } from '../../hooks/Cards/useCardsForList';
import useOrderItemsForCardsInList from '../../hooks/Lists/useOrderItemsForCardsInList';
import usePaginateCardsInList from '../../hooks/Cards/usePaginateCardsInList';

export default function CardsListFetch({ listID }: { listID: string }) {
    const { isLoading, isError, error, data } = useCardsForList(listID);
    const { data: orderData = { orderItems: []}} = useOrderItemsForCardsInList(listID);
    const pagesArray = usePaginateCardsInList(orderItems, data);

    return (
        ...
    );
}

Upvotes: 0

TkDodo
TkDodo

Reputation: 29056

The property on useQuery that you need to consume where you find your data is called data, so it should be:

const { data } = useOrderItemsForCardsInList(listID);

if that data has a property called orderItems, you can access it from there.

However, two things I'm seeing in your code:

  1. a conditional hook call of useQuery (which is forbidden in React)
  2. your queryFn returns any because fetch is untyped, so even though you are using TypeScript, you won't get any typesafety that way.

Upvotes: 6

Related Questions