AdeleD / react-paginate

A ReactJS component that creates a pagination
MIT License
2.75k stars 626 forks source link

How to update/reset the pagination every time I search in the search bar for list item? #478

Closed graydirt closed 1 year ago

graydirt commented 1 year ago

First I'm not sure if the functionality of my filter/search bar are correct.

Here are my concern, we have the words 'dolor' and 'dolorum' in the items of 25pages.

You can view it here.

Try to search the word "dolor" in the searchbar, the 25pages pagination is now 18pages. Then click the third pagination links and update your search to 'dolorum' in the searchbar, see the message says 'No Posts Found!' and the pagination is now 2pages. But we have 'dolorum' content in the items but it is only up to two pages of the pagination, and I think that is the reason why I got an error of 'No Posts Found!', because I clicked the third pagination links.

Is my code/functionality right? Is there any suggestions to avoid that bug in my code? maybe update the pagination/content items everytime I search?

Below is my code and to better understand here is the complete sandbox code https://codesandbox.io/. It's free to fork it!

Movielist.js

import { React, useState, useEffect } from "react";
import MovieListPagination from "./MovieListPagination";
import SearchBar from "./SearchBar";

const MovieList = () => {
  const [error, setError] = useState(null);
  const [isLoaded, setIsLoaded] = useState(false);
  const [items, setItems] = useState([]);
  const [searchResults, setSearchResults] = useState([]);

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/posts")
      .then((res) => res.json())
      .then(
        (result) => {
          setIsLoaded(true);
          setItems(result);
          setSearchResults(result);
          //console.log(result);
        },
        (error) => {
          setIsLoaded(true);
          setError(error);
        }
      );
  }, []);

  if (error) {
    return <div className="p-3">Error: {error.message}</div>;
  } else if (!isLoaded) {
    return <div className="p-3">Loading...</div>;
  } else {
    return (
      <>
        <SearchBar items={items} setSearchResults={setSearchResults} />
        <MovieListPagination dataProps={searchResults} itemsPerPage={4} />
      </>
    );
  }
};

export default MovieList;

MovielistPagination.js

import { React, useState } from "react";
import { Row, Alert } from "react-bootstrap";
import ReactPaginate from "react-paginate";
import MovieListItems from "./MovieListItems";

const MovieListPagination = ({ itemsPerPage, dataProps }) => {
  const [itemOffset, setItemOffset] = useState(0);
  const endOffset = itemOffset + itemsPerPage;
  const currentItems = dataProps.slice(itemOffset, endOffset);
  const pageCount = Math.ceil(dataProps.length / itemsPerPage);
  const handlePageClick = (event) => {
    const newOffset = (event.selected * itemsPerPage) % dataProps.length;
    setItemOffset(newOffset);
  };

  const results = currentItems.map((item) => (
    <MovieListItems key={item.id} items={item} />
  ));

  const content = results?.length ? (
    results
  ) : (
    <Alert variant="primary">No Posts Found!</Alert>
  );

  return (
    <>
      <Row className="justify-content-center">{content}</Row>

      <ReactPaginate
        breakLabel="..."
        nextLabel="›"
        onPageChange={handlePageClick}
        pageRangeDisplayed={3}
        marginPagesDisplayed={1}
        pageCount={pageCount}
        previousLabel="‹"
        renderOnZeroPageCount={null}
        containerClassName="justify-content-center pagination"
        previousClassName="page-item"
        previousLinkClassName="page-link"
        nextClassName="page-item"
        nextLinkClassName="page-link"
        pageClassName="page-item"
        pageLinkClassName="page-link"
        breakClassName="page-item"
        breakLinkClassName="page-link"
        activeClassName="active"
        disabledClassName="disabled"
      />
    </>
  );
};

export default MovieListPagination;

SearchBar.js

import { Form, Button } from "react-bootstrap";

const SearchBar = ({ items, setSearchResults }) => {
  const handleSubmit = (e) => e.preventDefault();

  const handleSearchChange = (e) => {
    if (!e.target.value) return setSearchResults(items);

    const resultsArray = items.filter(
      (item) =>
        item.title.includes(e.target.value.toLowerCase()) ||
        item.body.includes(e.target.value.toLowerCase())
    );

    setSearchResults(resultsArray);
  };

  return (
    <>
      <Form onSubmit={handleSubmit}>
        <Form.Group className="my-3">
          <Form.Control
            type="text"
            id="search"
            placeholder="Search here..."
            onChange={handleSearchChange}
          />
        </Form.Group>
      </Form>
    </>
  );
};
export default SearchBar;
MihirModi1421 commented 1 year ago

hello, @graydirt i am facing the same issue as you mentioned please share me solution regarding issue if you found any

Chandan9898Kumar commented 1 year ago

@graydirt, firstly it should not work like that . if you are at page 1 then while searching it should those data which are in page 1 .it should not search for next page.

Please do let me know, if you need any assistance

graydirt commented 1 year ago

@graydirt, firstly it should not work like that . if you are at page 1 then while searching it should those data which are in page 1 .it should not search for next page.

Please do let me know, if you need any assistance

@Chandan9898Kumar correct me if I'm wrong, so you mean my code/functionality is right? Is there any suggestions to avoid that I call bug in my code?:) maybe update the pagination/content items everytime I search?

Chandan9898Kumar commented 1 year ago

@graydirt just suppose if we have pagination and have 10 pages. So at page 1 we want show only 10 elements from index 0 to 10 and at page 2 we show elements from index 10 to 20 and so on.

ex- const [data,setData]=useState([] Here we are having 100 Datas

const [pageno,setPageNo] =useState(1) this is our current page no.

const paginatedData=data.slice(pageno10-10,pageno10).map((item)=>{ return( your items to be shown here )

})

now if i click on page 1 then i will get 10 elements only and will search only in these 10 elements.

I hope this will help you. Please do let know if you need any other help.

Thank you.

MihirModi1421 commented 1 year ago

Screenshot from 2023-04-25 10-02-54 @graydirt you can solve this search issue by giving key prop to reactPaginate component as pageCount changes it will reset to first page, hope it helps, it's a work around way but it works in your given code sandbox example. Also if you find any other solution let me know

graydirt commented 1 year ago

@graydirt just suppose if we have pagination and have 10 pages. So at page 1 we want show only 10 elements from index 0 to 10 and at page 2 we show elements from index 10 to 20 and so on.

ex- const [data,setData]=useState([] Here we are having 100 Datas

const [pageno,setPageNo] =useState(1) this is our current page no.

const paginatedData=data.slice(pageno_10-10,pageno_10).map((item)=>{ return( your items to be shown here )

})

now if i click on page 1 then i will get 10 elements only and will search only in these 10 elements.

I hope this will help you. Please do let know if you need any other help.

Thank you.

@Chandan9898Kumar Im just following your instructions, but Im confused:), can you fork my codesandbox link if its ok to you:)

graydirt commented 1 year ago

Screenshot from 2023-04-25 10-02-54 @graydirt you can solve this search issue by giving key prop to reactPaginate component as pageCount changes it will reset to first page, hope it helps, it's a work around way but it works in your given code sandbox example. Also if you find any other solution let me know

@MihirModi1421 hmm I added the key={pageCount}, but its not working, feel free to fork my codesandbox link..thx

Chandan9898Kumar commented 1 year ago

@graydirt Just worked on your issue - here is the solution. please do let me know if you were seeking this solution.

import { React, useState, useEffect } from "react"; import MovieListPagination from "./MovieListPagination"; import SearchBar from "./SearchBar";

const MovieList = () => { const [error, setError] = useState(null); const [isLoaded, setIsLoaded] = useState(false); const [items, setItems] = useState([]); const [searchResults, setSearchResults] = useState([]);

useEffect(() => { fetch("https://jsonplaceholder.typicode.com/posts") .then((res) => res.json()) .then( (result) => { setIsLoaded(true); setItems(result); setSearchResults(result); //console.log(result); }, (error) => { setIsLoaded(true); setError(error); } ); }, []);

if (error) { return

Error: {error.message}
; } else if (!isLoaded) { return
Loading...
; } else { return ( <>

    <MovieListPagination dataProps={items} itemsPerPage={4} />
  </>
);

} };

export default MovieList;

goldmont commented 1 year ago

@graydirt You have to set key={searchResults.length} on your MovieListPagination component.

https://65qqxe.csb.app

graydirt commented 1 year ago

It's working, I'm going to close this one. Thanks guys!