无法使用静态数据在React App中执行动态搜索

时间:2018-08-30 05:33:58

标签: javascript reactjs

我正在对我的React应用执行排序,过滤和分页,该应用显示json文件中的数据,其中包括电影数据。我能够从输入框中获取数据,但无法设置状态,也无法控制台日志searchKey和电影。

下面是App.js和Hello.js的代码。 App组件同时具有排序和搜索功能。

  

App.js

import data from './data.json';

class App extends Component {
  constructor() {
    super();
    this.state = {
      movies: data.movies, sort_term: '', searchKey: '', filterList: '',
    };
    this.onSorting = this.onSorting.bind(this);
    this.onSearchMovie = this.onSearchMovie.bind(this);
  }
  onSorting = (e) => {
    let term = 'Title';
    let option = e.target.value;
    let sortedList = [...this.state.movies].sort((a, b) => {
      return (option == 'asc' ? (a[term] <= b[term] ? -1 : 1) :
        (a[term] >= b[term] ? -1 : 1))
    });
    this.setState({ sort_term: term });
    this.setState({ movies: sortedList });
  }
  onSearchMovie(e) {
    let key = e;
     console.log(key);
     this.setState({searchKey : key });
     console.log(searchKey);
     let list = movies.filter(m =>{
       return m.Title.toLowerCase().includes(searchKey.toLowerCase());
     });
     this.setState({movies:list});
  }
  render() {
    const { movies } = this.state;

    if (!movies.length) {
      return (
        <div className="container">
          <h2>loading...</h2>
        </div>
      );
    }
    else {
      return (
        <div>
          <Hello sort_term={this.state.sort_term}
            onSorting={this.onSorting}
            onSearch={this.onSearchMovie} />
          <br />
          <Table movies={this.state.movies} />
        </div>
      );
    }
  }
}
  

Hello.js

class Hello extends Component {
  constructor(props) {
    super(props);
    this.state = { inputField: '', }
    this.onSubmitTitle = this.onSubmitTitle.bind(this);
    this.getTitle = this.getTitle.bind(this);
  }
  onSubmitTitle(e){
    e.preventDefault();
    this.props.onSearch(this.state.inputField);
    this.setState({ inputField: '' });
  }
  getTitle(e){
    this.setState({ inputField: e.target.value });
    // console.log('---');
  // console.log(this.state.inputField);
  }

  render() {
    const { sort_term, onSorting } = this.props;

    return (
      <div className="header">
        Database
        <ul className="navLeft">
          <li>
            <form onSubmit={this.onSubmitTitle}>
              <input type="search"  onChange={this.getTitle} value={this.state.inputField}
                className="search-bar"
                placeholder="Type for search..." />
            </form>
          </li>
          <li >
            <form >
              <select
                onChange={onSorting}
                className="searchBar">
                <option value="desc" >Sort Title(Z - A)</option>
                <option value="asc">Sort Title(A - Z)</option>
                 <option value="descDirector">Sort Director(Z - A)</option>
                <option value="ascDirector">Sort Director(A - Z)</option>
              </select>
            </form>
          </li>
        </ul>
      </div>
    );
  }
}

1 个答案:

答案 0 :(得分:2)

您遇到了几个问题:

  • 您在这里有一些未定义的变量:

            onSearchMovie(e) {
                let key = e;
                console.log(key);
                this.setState({ searchKey: key });
                console.log(searchKey);
                let list = movies.filter(m => {
                  return m.Title.toLowerCase().includes(searchKey.toLowerCase());
                });
                this.setState({ movies: list });
              }
    
     like `searchKey` and `movies`.
    
  • setState是异步的,因此请执行以下操作:

            this.setState({ sort_term: term });
            this.setState({ movies: sortedList });
    
            Is the same as doing this:  
    
    
            this.setState({
              sort_term: term,
              movies: sortedList
            });
    
  • 这句话说,此代码块可能无法按预期工作:

        onSearchMovie(e) {
          let key = e;
          console.log(key);
          this.setState({ searchKey: key });
          console.log(searchKey);
          let list = movies.filter(m => {
            return m.Title.toLowerCase().includes(searchKey.toLowerCase());
          });
          this.setState({ movies: list });
        } 
    

    由于如上所述,setState是异步的。因此this.state.searchKey可能不是您下一行访问时的想法。
    使用key变量或使用setState回调,它将在setState完成后触发。

    this.setState({someKey: someValue}, () => {console.log(this.state.someKey)})

    您可以在文档Why is setState giving me the wrong value?中阅读有关它的更多信息。

  • 您可能不知道的另一件事是,当您在{br />上使用onSubmit form实际上需要触发提交。既然你没有 您可以使用enter键来执行任何提交按钮。所以当你
    集中在input上,按【{1}】键,enter将 提交。

  • 我要做的另一件事是显示和更新form 列表而不是filteredMovis列表,因为一旦过滤 出物品,那么您就无法取回它们。因此,当您进行过滤时, 在movies上执行此操作,但不更新movies列表 从原始filteredMovis列表中删除项目。

这是一个运行中的示例:

movies
const data = {
  movies: [
    {
      id: 1,
      Title: "wonder woman"
    },
    {
      id: 2,
      Title: "kill bill"
    },
    {
      id: 3,
      Title: "world war z"
    },
    {
      id: 4,
      Title: "pixels"
    }
  ]
};

class Hello extends React.Component {
  constructor(props) {
    super(props);
    this.state = { inputField: "" };
    this.onSubmitTitle = this.onSubmitTitle.bind(this);
    this.getTitle = this.getTitle.bind(this);
  }
  onSubmitTitle(e) {
    e.preventDefault();
    this.props.onSearch(this.state.inputField);
    this.setState({ inputField: "" });
  }
  getTitle(e) {
    this.setState({ inputField: e.target.value });
    // console.log('---');
    // console.log(this.state.inputField);
  }

  render() {
    const { onSorting } = this.props;

    return (
      <div className="header">
        Database
        <ul className="navLeft">
          <li>
            <form onSubmit={this.onSubmitTitle}>
              <input
                type="text"
                onChange={this.getTitle}
                value={this.state.inputField}
                className="search-bar"
                placeholder="Type for search..."
              />
            </form>
          </li>
          <li>
            <form>
              <select onChange={onSorting} className="searchBar">
                <option value="desc">Sort Title(Z - A)</option>
                <option value="asc">Sort Title(A - Z)</option>
                <option value="descDirector">Sort Director(Z - A)</option>
                <option value="ascDirector">Sort Director(A - Z)</option>
              </select>
            </form>
          </li>
        </ul>
      </div>
    );
  }
}

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      movies: data.movies,
      filteredMovis: data.movies,
      sort_term: "",
      searchKey: "",
      filterList: ""
    };
    this.onSorting = this.onSorting.bind(this);
    this.onSearchMovie = this.onSearchMovie.bind(this);
  }
  onSorting = e => {
    let term = "Title";
    let option = e.target.value;
    let sortedList = [...this.state.movies].sort((a, b) => {
      return option == "asc"
        ? a[term] <= b[term]
          ? -1
          : 1
        : a[term] >= b[term]
          ? -1
          : 1;
    });
    this.setState({
      sort_term: term,
      filteredMovis: sortedList
    });
  };
  onSearchMovie(key) {
    const { movies } = this.state;
    let list = movies.filter(m => {
      return m.Title.toLowerCase().includes(key.toLowerCase());
    });
    this.setState({ filteredMovis: list, searchKey: key });
  }
  render() {
    const { filteredMovis, movies } = this.state;

    if (!movies.length) {
      return (
        <div className="container">
          <h2>loading...</h2>
        </div>
      );
    } else {
      return (
        <div>
          <Hello
            sort_term={this.state.sort_term}
            onSorting={this.onSorting}
            onSearch={this.onSearchMovie}
          />
          <br />
          {filteredMovis.map(movie => <div key={movie.id}>{movie.Title}</div>)}
        </div>
      );
    }
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);