在反应中查询为空时显示的项目

Items being displayed when query is empty in react

我正在学习 React,并且我使用 freecodecamp 的示例制作了一个示例电视节目应用程序。从我所看到的情况来看一切正常,但是在搜索某些内容然后退格搜索框中的所有内容后,它显示了不应该显示的结果,有人能看到我在代码中犯的错误吗?

class SeriesList extends React.Component {
  state = {
    series: [],
    query: ''
  }

  onChange = async e => {
    this.setState({query: e.target.value});
    const response = await fetch(
      `https://api.tvmaze.com/search/shows?q=${this.state.query}`
    );
    const data = await response.json();
    this.setState({series: data});
  }

  render(){
    return (
      <div>
        <input type="text" onChange={this.onChange} value={this.state.query} />
        <ul>
          <SeriesListItem list={this.state.series} />
        </ul>
      </div>
    );
  }
}

我在 codepen 上有它。

https://codepen.io/crash1989/pen/ERxPGO

谢谢

setState 异步工作。所以不能保证 this.state.query 在调用 this.setState({query: e.target.value}) 后已经更新。所以你的 url 最终包含了之前的状态。

有两种选择:

  1. 为新查询使用事件数据:

    const response = await fetch(
       `https://api.tvmaze.com/search/shows?q=${e.target.value}`
    );
    ...
    
  2. 使用 setState 回调第二个参数

    this.setState({query: e.target.value}, () => {
      const response = await fetch(
        `https://api.tvmaze.com/search/shows?q=${this.state.query}`
      );
      ...
    })
    

这是一篇关于 setState https://medium.com/@wereHamster/beware-react-setstate-is-asynchronous-ce87ef1a9cf3 的异步性质的好文章。

还有一点你可以使用 await 来设置状态

onChange = async e => {    
    await this.setState({query: e.target.value});
    const response = await fetch(
      `https://api.tvmaze.com/search/shows?q=${this.state.query}`
    );
    const data = await response.json();
    this.setState({series: data});
  }

您的请求将在更改查询后执行

问题

存在竞争条件:当您键入两个以上的字母时,您会进行两个以上的网络调用。第一个网络调用可能最后完成,然后显示错误查询的结果。

我用这支笔修复了它:https://codepen.io/arnemahl/pen/zaYNxv

解决方案

跟踪您曾经得到回复的所有查询的结果。总是如何为当前查询返回数据。 (另外,不要对同一个查询进行多次 API 调用,我们已经知道了)。

state: {
  seriesPerQuery: {}, // Now a map with one result for each query you look up
  query: [],
}

...

onChange = async e => {
  ...

  // Now keep the results of the old querys, in addition to the new one
  // whenever you get an API response
  this.setState(state => ({
    seriesPerQuery: {
      ...state.seriesPerQuery,
      [query]: data,
    }
  }));
}