'How to implement pagination and search in React
Good evening! I am creating simple React app using TS + React Query + Recoil. App is about 'online library'. I would like to create pagination and search input (to find specific author or title). My idea was, when app starts I am fetching data from page 1. Then when I'll click 2nd button on my pagination bar I'll fetch data from page 2 etc. Code looks like this:
Main component
import { useGetBooks } from '../../hooks/useGetBooks';
import { BookType } from '../../types/Book';
import { SingleBook } from './SingleBook';
import styled from 'styled-components';
import { Navbar } from './Navbar';
import { Loader } from '../utilities/Loader';
import { Error } from '../utilities/Error';
import { useState } from 'react';
import { useRecoilState } from 'recoil';
import { Books } from '../../recoil/globalState';
type bookType = BookType;
export const BookList = () => {
const [pageNumber, setPageNumber] = useState(1);
const [books, setBooks] = useRecoilState(Books);
const { isLoading, isError } = useGetBooks(pageNumber, setBooks);
if (isLoading) {
return <Loader isLoading={isLoading} />
}
if (isError) {
return <Error />
}
const displayBooks = books.data.map((book: bookType) => {
return (
<SingleBook key={book.id} book={book} />
)
})
return (
<BookContainer>
<div className='test'>
<button onClick={() => setPageNumber((page) => page - 1)} disabled={pageNumber == 1}>Prev page</button>
<p>{books.metadata.page}</p>
<button onClick={() => setPageNumber((page) => page + 1)} disabled={books.metadata.records_per_page * books.metadata.page > books.metadata.total_records}>Next page</button>
</div>
<Navbar />
<BookContent>
{displayBooks}
</BookContent>
</BookContainer>
)
}
React query:
import { useQuery } from "react-query";
import axios from 'axios';
const fetchBooks = async (pageNumber: number) => {
const res = await axios.get(`http://localhost:3001/api/book?page=${pageNumber}`);
return res.data
}
export const useGetBooks = (pageNumber: number, setBooks: any) => {
return useQuery(['books', pageNumber], () => fetchBooks(pageNumber),
{
onSuccess: (data) => setBooks(data),
keepPreviousData: true
})
}
Recoil:
import { atom } from 'recoil';
export const Books = atom({
key: 'book',
default: [] as any
})
And books response:
books: {
data: [
{
author: 'Some crazy',
title: 'Some crazy'
},
{
author: 'Some crazy1',
title: 'Some crazy1'
},
],
metadata: {
page: 1,
records_per_page: 10,
total_records: 17
}
}
Search Input Implementation:
import React, { useState } from "react"
import { useGetFilteredBooks } from "../../hooks/useGetFilteredBooks"
import { useRecoilState } from "recoil"
import { Books } from "../../recoil/globalState"
export const SearchBook = () => {
const [text, setText] = useState('')
const [books, setBooks] = useRecoilState(Books);
const { data, refetch } = useGetFilteredBooks(text, setBooks);
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setText(event.target.value)
}
const handleOnSubmit = (e: any) => {
e.preventDefault();
refetch();
}
return (
<>
<form onSubmit={handleOnSubmit}>
<Input value={text} onChange={handleOnChange} placeholder="Enter the name of the book or author" />
<button type="submit">Show</button>
</form>
<button onClick={() => console.log(books)}>plasda</button>
</>
)
}
React query:
import { useQuery } from "react-query";
import axios from 'axios';
const fetchFilteredsBooks = async (searchText: string) => {
const res = await axios.get(`http://localhost:3001/api/book?search=${searchText}`);
return res.data
}
export const useGetFilteredBooks = (searchText: string, setBooks: any) => {
return useQuery(['filteredBooks', searchText], () => fetchFilteredsBooks(searchText),
{
onSuccess: (data) => setBooks(data),
enabled: false
})
}
We can only display 10 items per 1 page.
PROBLEM:
When we search something and we get data back, we can have scenario, when data will need to be display not on 1 page. So when we have filtered data, and we click 2nd button on pagination, the filtered data will disapeared and we see not filtered data from page 2
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
