1

I am using React-Query with react, Now I am trying to do pagination but the component only renders on window focus. It is illustrated in the following video,

Illustration

Here we can see that the component only re-renders only after the window focus on how to fix that. Below is the code for the components,

The Query Hook,


// To get all the chats Details
export const useGetChats = ({
  userId,
  jwt,
  params,
}: {
  userId: number;
  jwt: string;
  params: {
    perPage: number;
    page: number;
    sortBy: string;
  };
}) => {
  // Query Key
  const queryKey = ['users', userId, 'chats'];

  // Response
  type ResponseType = IChat[];

  // Fetcher
  const fetcher = async () => {
    const QueryUrl = `/api/v1/users/${userId}/chats?perPage=${params.perPage}` +
    `&page=${params.page}&sortBy=${params.sortBy}`
    return await axios.get<ResponseType>(QueryUrl, {
      headers: { Authorization: `Bearer ${jwt}` }
    });
  };

  // Query
  return useQuery(queryKey, fetcher, { keepPreviousData: true });
};

The Chat View (List the chats),

interface IChatViewProps extends HTMLAttributes<HTMLDivElement> {
  setSortBy   : (shortBy: "name" | "createdAt" | "updatedAt") => void;
  sortBy      : "name" | "createdAt" | "updatedAt";
  isFetching  : boolean;
  onPrev?     : () => void;
  onNext?     : () => void;
  hasPrev     : boolean;
  hasNext     : boolean;
  chats       : IChat[] | null;
  onDelete?   : (chat: IChat) => void;
  onOpen?     : (chat: IChat) => void;
  onEdit?     : (chat: IChat) => void;
}


// Chat View
export default function ChatView({
  isFetching,
  setSortBy,
  sortBy,
  hasPrev,
  hasNext,
  chats,
  onPrev,
  onNext,
  onDelete,
  onOpen,
  onEdit,
}: IChatViewProps) {
  // sort change handler
  const handleSortChange = (event: SelectChangeEvent<"name" | "createdAt" | "updatedAt">) => {
    setSortBy(event.target.value as typeof sortBy);
  }

  // if chats are loading
  if (chats === null) {
    return <CircularProgress sx={{margin: "auto"}}/>;
  }

  // select Component for the sortBy
  const SelectSort = (
    <FormControl sx={{ m: 1, minWidth: 120 }} size="small">
      <InputLabel id="sort-by-label">Sort By</InputLabel>
      <Select
        onChange={handleSortChange}
        labelId="sort-by-label"
        value={sortBy}
        label="Sort By"
        id="sort-by-select"
      >
        <MenuItem value={"createdAt" as typeof sortBy}>
          Created At
        </MenuItem>
        <MenuItem value={"name" as typeof sortBy}>
          Name
        </MenuItem>
        <MenuItem value={"updatedAt" as typeof sortBy}>
          Updated At
        </MenuItem>
      </Select>
    </FormControl>
  )

  // chats component to render
  const UserChats = chats.map((chat: IChat) => {
    return (
      <React.Fragment>
        <HorizontalBar
          onDelete={onDelete}
          onOpen={onOpen}
          chat={chat}
          onEdit={onEdit}
        />
        <ChatDivider />
      </React.Fragment>
    );
  });

  // fetching status
  const Fetching = isFetching ? (
    <CircularProgress
      sx={{margin: "8px auto 0 7px"}}
      size={"1rem"}
    />
  ) : (
    null
  );

  // render
  return (
    <ChatViewWrapper>
      <Header>
        <Title>Your Chats List</Title>
        {Fetching}
        <Sort>{SelectSort}</Sort>
      </Header>
      <Body>
        {UserChats.length === 0 ? (
          <NoChats>No Chats</NoChats>
        ) : (
          UserChats
        )}
      </Body>
      <Footer>
        <Button disabled={!hasPrev || isFetching}
          variant="outlined"
          onClick={onPrev}
        >
          Prev
        </Button>
        <Button disabled={!hasNext || isFetching}
          variant="outlined"
          onClick={onNext}
        >
          Next
        </Button>
      </Footer>
    </ChatViewWrapper>
  );
}

The Dashboard,


export default function Dashboard() {
  // sort by state
  const [sortBy, setSortBy] = useState<"name" | "createdAt" | "updatedAt">("name");

  // page number
  const [pageNumber, setPageNumber] = useState<number>(1);

  // user details
  const user: IUser | null = useSelector(selectUser);

  // jwt token
  const jwt: string | null = useSelector(selectJwt);

  // if no user throw
  if (!user || !jwt) {
    throw new Error("No User found");
  }

  // chats for the dashboard
  const {
    isPreviousData : isPrevData,
    isError,
    data,
    error,
    isFetching,
  } = useGetChats({
    userId: user.userId,
    jwt: jwt,
    params: {
      page: pageNumber,
      perPage: 5, // it is a constant
      sortBy: sortBy,
    },
  });

  // if error throw
  if (isError) {
    throw new Error("Error in getting chats: " + error);
  }

  // Header Link
  const link = data ? data.headers["link"] : undefined;

  // on prev handler
  const onPrev = () => {
    setPageNumber(Math.max(pageNumber - 1, 0));
  }

  // on next handler
  const onNext = () => {
    if (!isPrevData && link?.includes("next")) {
      setPageNumber(pageNumber + 1);
    }
  };

  // body
  const Body = () => (
    <DashboardWrapper>
      <UserView
        onDelete={() => null}
        onEdit={() => null}
        user={user}
      />
      <ChatView
        onDelete={() => null}
        onOpen={() => null}
        onEdit={() => null}
        isFetching={isFetching}
        setSortBy={setSortBy}
        sortBy={sortBy}
        onPrev={onPrev}
        onNext={onNext}
        hasPrev={pageNumber > 1}
        chats={data?.data || null}
        hasNext={!isPrevData && link?.includes("next") || false}
      />
    </DashboardWrapper>
  );

  return (
    <React.Fragment>
      <Header />
      <Body />
      <Footer />
    </React.Fragment>
  );
}

I removed Css and some stuff But the complete code is available at github Thank You

1
  • 1
    Query key should include every parameter that you use inside your fetcher, including page in your case and all others. Commented Aug 11, 2022 at 13:18

2 Answers 2

1

You query key doesn't include all dependencies that you are also using in the query function. React-Query will only automatically trigger a refetch if the queryKey changes. This is documented in multiple places:

Sign up to request clarification or add additional context in comments.

Comments

0

pass refetchOnWindowFocus: false option to useQuery like this:

 return useQuery(queryKey, fetcher, 
{ 
  keepPreviousData: true,
  refetchOnWindowFocus: false 
});

also you can use react-query-useful-hooks, so that you don't have such problems.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.