react:搜索和过滤功能的问题

IT技术 javascript reactjs data-binding bind
2021-05-08 23:26:10

我正在开发一个应该能够:

  1. 按输入搜索 - 使用输入字段,在触发 onBlur 事件后将调用一个函数。onBlur事件之后startSearch () 方法将运行。

  2. 按所选流派过滤 - 从其他组件,用户可以从流派列表中选择流派。onClick事件之后startFilter () 方法将运行。

好消息: 我得到了上面的 2 个功能。

坏消息: 上述 2 个函数不能正常工作。请看下面的代码。下面的 2 个调用有效,但前提是我将 2 个中的一个注释掉。我试图以各种方式调整startSearch () 方法,但我只是一直走到一个大胖墙。

//////Searching works
//////this.filter(this.state.searchInput);

//Filtering works           
this.startFilter(this.state.searchInput);

问题 我怎样才能使过滤器/搜索方法起作用?. 不幸的是,简单地将它们放在 if/else 中不是解决方案(请参阅代码中的注释)。

import { Component } from 'preact';
import listData from '../../assets/data.json';
import { Link } from 'preact-router/match';
import style from './style';

export default class List extends Component {
  state = {
    selectedStreamUrl: '',
    searchInput: '',
    showDeleteButton: false,
    searchByGenre: false,
    list: []
  };

  startFilter(input, filterByGenre) {
    this.setState({
      searchByGenre: true,
      searchInput: input,
      showDeleteButton: true
    });
    alert('startFilter  ');
    console.log(this.state.searchByGenre);
    /////////---------------------------------
    document.getElementById('searchField').disabled = false;
    document.getElementById('searchField').value = input;
    document.getElementById('searchField').focus();
    // document.getElementById('searchField').blur()
    document.getElementById('searchField').disabled = true;

    console.log(input);
    this.filter(input);
  }

  //search
  startSearch(input) {
    alert('startSearch  ');
    console.log(this.state.searchByGenre);

    //komt uit render()
    if (!this.state.searchByGenre) {
      //check for input

      this.setState({
        searchInput: input.target.value,
        showDeleteButton: true
      });

      //Searching works
      //this.filter(this.state.searchInput);

      //Filtering works
      this.startFilter(this.state.searchInput);

      // DOESNT WORK:
      // if (this.state.searchInput != "") {
      // 	this.filter(this.state.searchInput);
      // } else {
      // 	this.startFilter(this.state.searchInput);
      // }
    }
  }

  setAllLists(allLists) {
    console.log('setAllLists');
    console.log(this.state.searchByGenre);
    this.setState({ list: allLists });
    //document.body.style.backgroundColor = "red";
  }

  filter(input) {
    let corresondingGenre = [];
    let filteredLists = listData.filter(item1 => {
      var test;
      if (this.state.searchByGenre) {
        alert('--this.state.searchByGenre');
        //filterByGenre
        //& item1.properties.genre == input

        for (var i = 0; i < item1.properties.genre.length; i++) {
          if (item1.properties.genre[i].includes(input)) {
            corresondingGenre.push(item1);
            test = item1.properties.genre[i].indexOf(input) !== -1;

            return test;
          }
          this.setState({ list: corresondingGenre });
        }
      } else {
        //searchByTitle
        alert('--default');
        test = item1.title.indexOf(input.charAt(0).toUpperCase()) !== -1;
      }
      return test;
    });
    console.log('filterdLists:');
    console.log(filteredLists);
    console.log('corresondingGenre:');
    console.log(corresondingGenre);
    //alert(JSON.stringify(filteredLists))
    this.setState({ list: filteredLists });
  }

  removeInput() {
    console.log('removeInput    ');
    console.log(this.state.searchByGenre);
    this.setState({
      searchInput: '',
      showDeleteButton: false,
      searchByGenre: false
    });
    document.getElementById('searchField').disabled = false;
    this.filter(this.state.searchInput);
  }

  render() {
    //alle 's komen in deze array, zodat ze gefilterd kunnen worden OBV title.
    if (
      this.state.list === undefined ||
      (this.state.list.length == 0 && this.state.searchInput == '')
    ) {
      //init list
      console.log('render ');
      console.log(this.state.searchByGenre);
      this.filter(this.state.searchInput);
    }

    return (
      <div class={style.list_container}>
        <input
          class={style.searchBar}
          type="text"
          id="searchField"
          placeholder={this.state.searchInput}
          onBlur={this.startSearch.bind(this)}
        />

        {this.state.searchByGenre ? <h1>ja</h1> : <h1>nee</h1>}
        {this.state.showDeleteButton ? (
          <button class={style.deleteButton} onClick={() => this.removeInput()}>
            Remove
          </button>
        ) : null}
        {this.state.list.map((item, index) => {
          return (
            <div>
              <p>{item.title}</p>
            </div>
          );
        })}
      </div>
    );
  }
}

3个回答

你问的问题不清楚。但是尝试明确您的组件以帮助调试问题。例如,使用构造函数并在其中声明您的组件状态。还要为那里的事件做 .bind 以使其简洁。

下面的例子在 onBlur 事件被触发时捕获状态变量为真,这与其初始状态值相同:

class List extends React.Component {
constructor(props) {
    super(props);
    this.state = {
        searchByGenre: true
    };

    this.startSearch = this.startSearch.bind(this);
}

startSearch() {
    // This value is true
    console.log(this.state.searchByGenre)
}

render() {
    return (
        <input 
            type="text" 
            id="searchField" 
            placeholder="Search" 
            value={this.state.searchInput} 
            onBlur={this.startSearch} 
        />
    )
}

为了使您的搜索和过滤器正常工作,您需要两个数组。

state = {
  selectedStreamUrl: "",
  searchInput: "",
  showDeleteButton: false,
  // searchByGenre: false, // removed, will use filter by from a list
  // by default both arrays have the same value
  list: listData, // holds the original data, doesn't change
  filteredList: listData, // holds filterd list, filtered when the user types in input
  // by default filter by title, will change when user, use a value from a list
  filterBy: 'title', 
}

您的搜索功能将使用this.state.filterBy值来过滤数组。无需创建多个函数。这为您提供了灵活性,因为您可以使用下拉列表中的多个值进行过滤,而不必更改代码。

startSearch = (value) => {

  const search = value.toLowerCase();
  // get filter value title, genre, etc
  const searchKey = this.state.filterBy;

  this.setState({
    searchInput: value,
    filteredList: this.state.list.filter(item => {
      // filter base on key item['title'] or item['genre'] etc
      return item && item[searchKey].toLowerCase().includes(search)
    }),
    showDeleteButton: !!value,
  })

}

移除输入功能

removeInput = () => {
  this.setState({
    filterBy: 'title',
    showDeleteButton: false,
    searchInput: '',
  }, () => this.startSearch(this.state.searchInput));
}

我看到你做了很多document.getElementById("searchField").disabled = false;不要直接操作 dom,让 react 为您管理。

见下面的演示

两种方式:

将绑定更改为构造函数(以及状态!)

constructor(props) {
        super(props);

        this.state = { searchByGenre: true }

        this.startSeach = startSearch.bind(this);
    }

    startSearch(searchByGenre) {
        //This is false after the call 
        console.log(this.state.searchByGenre)
    }

    render() {
        return (
            <input class={style.searchBar} type="text" id="searchField" placeholder="Search" value={this.state.searchInput} onBlur={this.startSearch} >
            </input>
        )
    }

这样你就可以使用startSearchwith 参数:

<input class={style.searchBar} 
  type="text" 
  id="searchField" 
  placeholder="Search" 
  value={this.state.searchInput} 
  onBlur={() => this.startSearch(this.state.searchByGenre)} 
>

或者,您可以将 更改为startSearch箭头函数,并从构造函数中删除绑定:

startSearch = (searchByGenre) => {
  //This is false after the call 
  console.log(this.state.searchByGenre)
}

您可以在此处查看为什么会发生这种情况

编辑:该链接讨论了 typeScript,但忽略它并专注于箭头函数/绑定部分