Reactjs Поиск после onChange - PullRequest
0 голосов
/ 03 января 2019

Я реализовал небольшую функциональность поиска в моем приложенииactjs. Проблема в том, что моя функция «searchHandler» запускается после каждой буквы, которую пользователь вводит в текстовое поле ... Так, например, для термина "Lorem" моя функция извлекается из моего API 5 раз: (

Как я могу решить эту проблему?

Вот мой код:

const { scaleDown } = transitions;

function searchingFor(term){

return function(x){
return x.title.toLowerCase().includes(term.toLowerCase()) ||
x.body.toLowerCase().includes(term.toLowerCase());
}

 }  


class ViewAll extends React.Component{

constructor(props){
  super(props);
  this.state = {
    term: '',
    mounted: true,
    tracks: [],
    hasMoreItems: true,
    page: 2,

  }

  this.searchHandler = this.searchHandler.bind(this);
  this.focus = this.focus.bind(this);
  this.keyPress = this.keyPress.bind(this);


 }

  loadContent() {
    var requestUrl = this.props.url;
    fetch(requestUrl + this.state.page + '&_limit=3').then((response)=>{
        return response.json();
    }) .then((tracks)=>{
        this.setState({ tracks: this.state.tracks.concat(tracks)});
        this.setState({page: this.state.page + 1});

        if(this.state.page === 6){
         this.setState({hasMoreItems: false})
       }
    }).catch((err)=>{
        console.log("There has been an error");
    });
}

componentDidMount() {
  window.scrollTo(0, 0);

var requestUrl = this.props.url;
fetch(requestUrl + '1&_limit=3')
    .then((response)=>{
    return response.json();
}) .then((data)=>{
    this.setState({tracks : data});

})
.catch((err)=>{
    console.log("There has been an error");
});

//this.focus();

 }
  searchHandler(event){
    this.setState({term: event.target.value});

    var requestUrl = 'https://questdb.herokuapp.com/all?q='
    fetch(requestUrl + this.state.term).then((response)=>{
        return response.json();
    }) .then((tracks)=>{
        this.setState({ tracks: this.state.tracks.concat(tracks)});


    }).catch((err)=>{
        console.log("There has been an error");
    });

  }

   focus() {
   this.textInput.focus();
 }


    keyPress(e){
       if(e.keyCode == 13){
          console.log('value', e.target.value);
          // put the login here
       }
    }    


render() {   


  const {term, data, tracks} = this.state;

  const loader = <div className="loader2"> </div>;

  var items = [];
  const imageUrl = require(`../assets/Book.jpg`)

  tracks.filter(searchingFor(term)).map(function(title, i)
{
    items.push(
            <div>
              <MuiThemeProvider>
                <Paper style={{ borderRadius: "2em",
                  background: '#ffffff'
                }} zDepth={1} >

          <ItemViewAll
            key={title.id}
              />
      </Paper>
      </MuiThemeProvider>
      </div>
    );
  }, this);



    return (
      <div>    

            <Fade in={true}  timeout={1000}>

<div >

  <MuiThemeProvider>

    <TextField hintText='Bot suchen...'

         type="Text"
         onChange={this.searchHandler}
         value={term}
         underlineFocusStyle={{borderColor: '#B00020', borderWidth: 3}}
         underlineStyle={{borderColor: '#B00020', borderWidth: 1.5, top: '45px'}}
         hintStyle={{fontSize: '8.1vw', fontFamily: 'Anton', color: 'rgba(255,255,255,0.9)'}}
         inputStyle={{fontSize: '8.1vw', fontFamily: 'Anton', color: '#ffffff'}}
         ref={(input) => { this.textInput = input; }}
         style={{caretColor: '#ffffff', width: '90%', maginLeft: 'auto', marginRight: 'auto', marginTop: '12%' }}
         InputLabelProps={{ shrink: true }}
         />


     </MuiThemeProvider>
      </div>
      </Fade>   



    <InfiniteScroll
       pageStart={1}
       loadMore={this.loadContent.bind(this)}
       hasMore={this.state.hasMoreItems}
       initialLoad={true}

      >


              {items}
         </InfiniteScroll>    


</div>
    )
  }
}

export default ViewAll;

Здесь вы можете проверить сайт с неработающей функцией поиска. Как видите, элементы показаны двойными или даже тройными ... После очистки текстового поля результаты поиска должны быть удалены, и должны отображаться только обычные выбранные.

https://www.genko.de (используйте мобильную версию в Chrome)

Спасибо:)

Ответы [ 2 ]

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

Если вам не нужен полный пакет lodash, вы можете написать его самостоятельно:

function debounce(f, ms) {

  let timer = null;

  return function (...args) {
    const onComplete = () => {
      f.apply(this, args);
      timer = null;
    }

    if (timer) {
      clearTimeout(timer);
    }

    timer = setTimeout(onComplete, ms);
  };
}

Первый аргумент (f) - это ваша функция, которую не следует выполнять чаще, чем второй аргумент (мс) -количество мс).Так что в вашем случае вы можете написать свой обработчик следующим образом:

handleChange = debounce((e) => {
  const val = e.target.value

  this.setState({ value: val }, () => {
    this.changeSearch(val)
  })
}, 1000) // second arg (1000) is your amount of ms
0 голосов
/ 03 января 2019

Используйте lodash debounce.Используется для этого точного варианта использования

https://stackoverflow.com/questions/48046061/using-lodash-debounce-in-react-to-prevent-requesting-data-as-long-as-the-user-is

Образец:

import React, {Component} from 'react'
import { debounce } from 'lodash'

class TableSearch extends Component {

  //********************************************/

  constructor(props){
    super(props)

    this.state = {
        value: props.value
    }

    this.changeSearch = debounce(this.props.changeSearch, 250)
  }

  //********************************************/

  handleChange = (e) => {
    const val = e.target.value

    this.setState({ value: val }, () => {
      this.changeSearch(val)
    })
  }

  //********************************************/

  render() {

    return (
        <input
            onChange = {this.handleChange}
            value = {this.props.value}
        />
    )
  }

  //********************************************/

}
...