I have followed this example:
https://react-query-v3.tanstack.com/guides/paginated-queries
However, when I have tried doing it myself, the next button is always disabled? so I can't click next. my code is below:
import React, { useState } from 'react';
import { render } from 'react-dom';
import { useQuery } from 'react-query';
import axios from 'axios';
import { QueryClient, QueryClientProvider} from 'react-query';
const App: React.FunctionComponent = () => {
const queryKey = 'getData';
const [page, setPage] = React.useState(1)
const getDataFunction = async (page): Promise<any> => {
const response = await axios
.get(
`https://jsonplaceholder.typicode.com/posts?_limit=10&_page=${page}`
)
.then((res) => res.data);
return response;
};
const {
data: result,
isFetching,
status,
error,
refetch,
isPreviousData,
}: any = useQuery([queryKey, page], () => getDataFunction(page), {
keepPreviousData : true,
refetchOnWindowFocus: false,
});
return (
<div className="Container" >
<button onClick={refetch}>Refetch query</button>
{status === 'error' && <div className="mt-5">{error.message}</div>}
{isFetching ? (
<div className="mt-5">Loading data ...</div>
) : (
<div style={{height: 'auto', border: '1px solid', padding: '15px', margin: '10px 0px 10px 0px'}}>
{status === 'success' && (
<div>
<p>
{result?.map((inner, index) => {
return (
<div key={index}>
<p>
{inner?.id}
<br />
<strong>{inner?.title}</strong> <br />
{inner?.body}
</p>
</div>
);
})}
</p>
<p>{result?.title}</p>
</div>
)}
</div>
)}
<span>Current Page: {page}</span>
<button
onClick={() => setPage(old => Math.max(old - 1, 0))}
disabled={page === 1}
>
Previous Page
</button>{' '}
<button
onClick={() => {
if (!isPreviousData && result?.hasMore) {
setPage(old => old 1)
}
}}
// Disable the Next Page button until we know a next page is available
disabled={isPreviousData || !result?.hasMore}
>
Next Page
</button>
</div>
);
};
const queryClient = new QueryClient();
render(
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>,
document.getElementById('root')
);
Any idea's?
CodePudding user response:
In their example the response from the server contained hasMore
flag, in your case you don't have it, you have just set of data.
So the only way you could check if the next page is available is by checking if length
of the data returned to you is equals page size (it is not perfect, because it might be that the last available page contains 10 items, so the next page will have 0, but it is the only thing you can do here).
So basically you need
const hasNext = result?.length == 10;
And then use it
<button
onClick={() => {
if (!isPreviousData && hasNext) {
setPage((old) => old 1);
}
}}
// Disable the Next Page button until we know a next page is available
disabled={!hasNext}
>
Next Page
</button>
See https://stackblitz.com/edit/react-ts-ggyyg8?file=index.tsx
CodePudding user response:
hasMore
is not a value from react-query
, it should be returned from your server to tell your frontend that you have more data in the next page.
Your example API does not return anything in result.hasMore
, that is why the button has remained disabled.
I assume typicode returns a max of 100 items, so you can do this to use the limit and page number as a reference
import React, { useState } from 'react';
import { render } from 'react-dom';
import { useQuery } from 'react-query';
import axios from 'axios';
import { QueryClient, QueryClientProvider} from 'react-query';
const App: React.FunctionComponent = () => {
const queryKey = 'getData';
const [page, setPage] = React.useState(1)
const [limit] = React.useState(10)
const getDataFunction = async (page): Promise<any> => {
const response = await axios
.get(
`https://jsonplaceholder.typicode.com/posts?_limit=${limit}&_page=${page}`
)
.then((res) => res.data);
return response;
};
const {
data: result,
isFetching,
status,
error,
refetch,
isPreviousData,
}: any = useQuery([queryKey, page], () => getDataFunction(page), {
keepPreviousData : true,
refetchOnWindowFocus: false,
});
return (
<div className="Container" >
<button onClick={refetch}>Refetch query</button>
{status === 'error' && <div className="mt-5">{error.message}</div>}
{isFetching ? (
<div className="mt-5">Loading data ...</div>
) : (
<div style={{height: 'auto', border: '1px solid', padding: '15px', margin: '10px 0px 10px 0px'}}>
{status === 'success' && (
<div>
<p>
{result?.map((inner, index) => {
return (
<div key={index}>
<p>
{inner?.id}
<br />
<strong>{inner?.title}</strong> <br />
{inner?.body}
</p>
</div>
);
})}
</p>
<p>{result?.title}</p>
</div>
)}
</div>
)}
<span>Current Page: {page}</span>
<button
onClick={() => setPage(old => Math.max(old - 1, 0))}
disabled={page === 1}
>
Previous Page
</button>{' '}
<button
onClick={() => {
if (!isPreviousData && (page * limit) < 100) {
setPage(old => old 1)
}
}}
// Disable the Next Page button until we know a next page is available
disabled={isPreviousData || (page * limit) >= 100}
>
Next Page
</button>
</div>
);
};
const queryClient = new QueryClient();
render(
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>,
document.getElementById('root')
);