Jota
Jota

Reputation: 865

How to do an filter onChange in ReactJS?

I have the code below filterNames()

filterNames() {
    const { peoples } = this.state;
    this.setState({
      filtered: peoples.filter(item => item.name.includes(this.state.input)),
      currentPage:0
    });
    console.log(this.state.filtered)
} 

That filters when I click this button

button:

<button className='search' onClick={this.filterNames}>
    Search
</button>

Input:

<input type="text" onChange={ this.getValueInput }></input>

I want it where when I type the letter 'a' on input, it filters.

Resuming: I want to filter without clicking the button, just when I type on input.

My code all:

class Pagination extends React.Component {
  constructor() {
    super();
         
    const peoples = [
      {id:0, name:"Jean"}, 
      {id:1, name:"Jaquinha"}, 
      {id:2, name:"Ricardo"}, 
      {id:3, name:"JaCA"}, 
      {id:4, name:"Letiiicia"}, 
      {id:5, name:"Dai"}, 
      {id:6, name:"Da iIIane"}, 
      {id:7, name:"Tamy"}, 
      {id:8, name:"Tamyresss"},
      {id:9, name:"Tamyres"}, 
      {id:10, name:"Abeu"}, 
      {id:11, name:"Abellll"}
    ];
    
    this.state = {
      elementsPerPage:3,
      currentPage:0,
      peoples,
      input: "",
      filtered: peoples,
    };

    this.nextPage = this.nextPage.bind(this);
    this.previousPage = this.previousPage.bind(this);
    this.filterNames = this.filterNames.bind(this);
    this.getValueInput = this.getValueInput.bind(this);
  } 
  
  getValueInput (value) {
    this.setState({ input: value.target.value });
  }
    
  filterNames() {
    const { peoples } = this.state;
    this.setState({
      filtered: peoples.filter(item => item.name.includes(this.state.input)),
      currentPage:0
    });
    console.log(this.state.filtered)
  } 
  
  elementsOnScreen() {
    const { elementsPerPage, currentPage, filtered } = this.state;
    return filtered
      .map((item) => <li key={item.id}> {item.name} <button onClick={() => this.remove(item.name)}> Delete </button> </li>)
      .slice(currentPage*elementsPerPage, currentPage*elementsPerPage + elementsPerPage);
    
    if (this.state.filtered.length < 1) {
      this.setState({currentPage: this.state.currentPage - 1})
    }
  }

  remove = (id) => {
    console.log(this.state.filtered.length)
    if (this.state.filtered.length < 0) {
       this.setState({currentPange: this.state.currenPage - 1})
    }
    this.setState({filtered: this.state.filtered.filter(item => item.name !== id) })
  }
  
  nextPage() {
    console.log(this.state.filtered)

    const {elementsPerPage, currentPage, filtered} = this.state;
    
    if ((currentPage+1) * elementsPerPage < filtered.length){
      this.setState({ currentPage: this.state.currentPage + 1 });
    }
  }
  
  previousPage () {
    const { currentPage } = this.state;
    if(currentPage - 1 >= 0){
      this.setState({ currentPage: this.state.currentPage - 1 });
    }
  }

  render() {
    return (
      <div>
        <input type="text" onChange={ this.getValueInput }></input>
        <button className='search' onClick={this.filterNames}> Search </button>
        <button onClick={this.previousPage}> Previous </button>
        <button onClick={this.nextPage}> Next </button>
        <h3>Current Page: {this.state.currentPage}</h3>
        <ul>Names: {this.elementsOnScreen()}</ul>
      </div>
    );
  }
}


ReactDOM.render(
  <Pagination/>,
  document.getElementById('root')
)
<div id="root"></div>

Upvotes: 2

Views: 8769

Answers (1)

Kenneth Truong
Kenneth Truong

Reputation: 4166

You can update your getValueInput to handle the filtering.

getValueInput (evt) {
  const inputValue = evt.target.value;
  this.setState({ input: inputValue });
  this.filterNames(inputValue);
}

filterNames (inputValue) {
  const { peoples } = this.state;
  this.setState({
    filtered: peoples.filter(item => 
       item.name.includes(inputValue)),
    currentPage:0
  });
}

Note: You have to pass in the inputValue because React batches the setState calls. If you check, your this.state.input will still be your previous value even after calling setState. Which is why you have to rely on the evt.target.value in filterNames

Dan gives a good brief explanation here about how React batches setState calls. https://github.com/facebook/react/issues/10231#issuecomment-316644950

Upvotes: 2

Related Questions