Как применить фильтр ко всем разбитым на страницы элементам и отображать только отфильтрованные элементы? - PullRequest
0 голосов
/ 13 января 2019

Когда я применяю фильтры, он работает только на первой странице элементов. Когда я загружаю больше элементов, фильтр исчезает, и мне приходится снова нажимать фильтр, что, очевидно, не очень хорошо. Я хочу нажать «Фильтр» только один раз, и он вернет все элементы, которые соответствуют критериям.

Сейчас API, над которым я работаю, содержит чуть более 200 элементов. Должен ли я просто сделать 3 вызова API-интерфейса с нумерацией страниц, чтобы загрузить все элементы в API и объединить их в мастер-массив, а затем отфильтровать из этого локального мастер-массива? Таким образом, он будет отображать каждый отфильтрованный элемент на странице.

Но скажем, у меня есть API с гораздо большей базой данных с несколькими тысячами точек данных, тогда я не хочу загружать все в локальный массив. Я хотел бы знать, как фильтровать все разбитые на страницы элементы сразу и отображать только отфильтрованные элементы.

Вот мой код:

import React, {Component} from 'react';
import axios from 'axios';
import BookList from './BookList';
import LoadingButton from './LoadingButton';
import FilterButton from './FilterButton';

    const root_api = "...";
    const books_per_page = 15;

    class HomePage extends Component{
      constructor(props){
        super(props);
        this.state ={
        books:[],
        pageNum: 1,
        isLoading: false,
        isDataFetched: false,
        isListComplete: false,
        error:''};
    }
    //get 15 items at a time
    getBooks(){
      const requestUrl = `${root_api}books?page=${
        this.state.pageNum
      }&per_page=${book_per_page}`;  
      this.setState({
        isLoading: true
      });
      axios.get(requestUrl)
      .then(res=>{
            res.data.length > 0
              ? this.setState({
                  books: [...this.state.books, ...res.data],
                  isLoading: false,
                  isDataFetched: true,
                  pageNum: this.state.pageNum + 1
                })
              : this.setState({
                  isLoading: false,
                  isDataFetched: true,
                  isListComplete: true
                });
      })

      .catch(err => {
        console.log(err);
        this.setState({

          isLoading: false,
          isDataFetched: false,
          error: err.message
        });
      });

    }

    filterBooks(){
      let newList =[];
      let currentList = [];
      currentList = this.state.books;
      newList = currentList.filter(function(book){
        return book.pages > 1200; 
      });
      this.setState({books: newList});
    }

    render(){

       return(
         <div>
         <FilterButton 
             isLoading={this.state.isLoading}
             isListComplete={this.state.isListComplete}
             clickHandler={()=>this.filterBooks()}
              />
           {this.state.books.length > 0 &&(
             <BookList books={this.state.books} />)}
           <LoadingButton
              isLoading={this.state.isLoading}
              isListComplete={this.state.isListComplete}
              clickHandler={()=>this.getBooks()}
           />
           }
         </div>
       )

}}

1 Ответ

0 голосов
/ 13 января 2019

Вам не нужно создавать основной локальный массив, просто еще одну переменную state, чтобы отслеживать, хочет ли пользователь отфильтровать книги:

constructor(props){
    super(props);
    this.state ={
        books:[],
        pageNum: 1,
        isLoading: false,
        isDataFetched: false,
        isListComplete: false,
        error:'',
        filtered: false // this is the new variable
    };
}

А также изменить некоторые функции:

getBooks(){
    const requestUrl = `${root_api}books?page=${
        this.state.pageNum
    }&per_page=${book_per_page}`;  
    this.setState({
        isLoading: true
    });
    axios.get(requestUrl)
    .then(res=>{
        let newState = {
            isDataFetched: true,
            isLoading: false
        }
        if (res.data.length > 0) {
            newState.pageNum = this.state.pageNum + 1
            newState.books = [
            ...this.state.books, 
            ...res.data
            ]
        } else {
            newState.isListComplete = true
        }
        this.setState(newState);
    }).catch(err => {
        console.log(err);
        this.setState({
            isLoading: false,
            isDataFetched: false,
            error: err.message
        });
    });
}

filterBooks(){
    this.setState(prevState => ({
        filtered: !prevState.filtered
    }));
}

РЕДАКТИРОВАТЬ: И изменить метод рендеринга:

render() {
    let bookListView
    if (this.state.books.length > 0) {
        let bookArr = this.state.books
        if (this.state.filtered) {
            bookArr = bookArr.filter(item => item.pages > 1200)
        }
        bookListView = <BookList books={bookArr} />
    }

    return(
        <div>
            <FilterButton 
                isLoading={this.state.isLoading}
                isListComplete={this.state.isListComplete}
                clickHandler={()=>this.filterBooks()}
            />
            {bookListView}
            <LoadingButton
                isLoading={this.state.isLoading}
                isListComplete={this.state.isListComplete}
                clickHandler={()=>this.getBooks()}
            />
        </div>
    )
}

РЕДАКТИРОВАТЬ: Я переместил фильтрующую часть в метод render, так что если ваш пользователь хочет отфильтровать свои результаты.

...