What am I looking for? 一种在 input 元素上使用 setState() 的方法,该元素使用 onChange 立即更新 state .

What have I done so far?

我有两个组件, BooksAppSearchBook . 我将 result 传递给 SearchBook 作为要渲染的道具 . 然后我使用 onChange 捕获 input 元素上的更改 . onChange 也在调用我作为道具传递的方法 . React documentation说如下,但是如果我使用回调然后在回调中我调用 setState() 听起来我回到了同样的情况,因为 setState() 将再次异步:

setState()并不总是立即更新组件 . 它可以批量推迟更新或推迟更新 . 这使得在调用setState()之后立即读取this.state是一个潜在的陷阱 . 相反,使用componentDidUpdate或setState回调(setState(更新程序,回调)),其中任何一个都保证在应用更新后触发 . 如果需要根据以前的状态设置状态,请阅读下面的updater参数 .

What is the issue? 如果用户过快地删除 input 的内容,虽然控制台中仍然存在 console.log('empty') ,但 setState() 不会运行,因此 result 保持不变并且不会变为空数组 .

这是 App.js 的内容:

class BooksApp extends Component {
  state = {
    books: [],
    result: [],
    query: ''
  }
  updateQuery = (query) => {
    this.setState({ query: query.trim() })
  }
  objDigger = (arr, diggers) => {
    const digged = [];
    diggers.forEach((d) => {
      let o = {};
      o = arr.filter((a) => a.id === d);
      o.forEach((i) => {
        digged.push(i);
      })
    });
    return digged;
  }
  filterHelper = (result) => {
    const resultKeys = result.map((r) => r.id)
    const stateKeys = this.state.books.map((s) => s.id)
    // this.objDigger(this.state.books, stateKeys)

    // new books
    const newKeys = _array.difference(resultKeys, stateKeys);
    const newObjs = this.objDigger(result, newKeys)

    // existing books
    const existingKeys = _array.difference(resultKeys, newKeys)
    const existingObjs = this.objDigger(this.state.books, existingKeys);

    // search books
    const searchObjs = newObjs.concat(existingObjs);
    return searchObjs;
  }
  searchBook = (query) => {
    this.updateQuery(query);
    if (query) {
      BooksAPI.search(query).then((result) => {
        result = this.filterHelper(result)
        if (!result.error) {
          this.setState({
            result,
          })
        }
      })
    } else {
      console.log('empty');
      this.setState(state => ({
        result: []
      }));
    }
  }
  appHandleChange = (query) => {
    console.log('searching');
    this.searchBook(query);
  }
  render() {
    return (
      <div className="app">
        <Route path="/search" render={() => (
          <SearchBook
            result={ this.state.result }
            onChange={ this.appHandleChange }
            onChangeShelf={ this.changeShelf }/>
        )}>
        </Route>
      </div>
    )
  }
}

这是 SearchBook 的内容:

class SearchBook extends Component {
  handleChange = (book, newShelf) => {
    this.props.onChangeShelf(book, newShelf);
  }
  handleInputChange = (event) => {
    this.props.onChange(event.target.value);
  }
  render() {
    const { result } = this.props;

    return (
      <div className="search-books">
        <div className="search-books-bar">
          <Link
            to="/"
            className="close-search"
          >
            Close
          </Link>
          <div className="search-books-input-wrapper">
            <input
              type="text"
              placeholder="Search by title or author"
              onChange={ (event) => this.handleInputChange(event) }
            />

          </div>
        </div>

        <div className="search-books-results">
          <ol className="books-grid">
            {result.length>0 && result.map((book) => (
              <li key={book.id}>
                <div className="book">
                  <div className="book-top">
                    <div className="book-cover" style={{ width: 128, height: 193, backgroundImage: `url(${book.imageLinks && book.imageLinks.smallThumbnail})` }}></div>
                    <BookShelfChanger
                      shelf={book.shelf ? book.shelf : 'none'}
                      onChangeShelf={(newShelf) => {
                        this.handleChange(book, newShelf)
                      }}
                    ></BookShelfChanger>
                  </div>
                  <div className="book-title">{book.title}</div>
                  <div className="book-authors">{book.authors}</div>
                </div>
              </li>
            ))}
          </ol>
        </div>
      </div>
    )
  }
}