【问题标题】:Clear state on selecting dropdown选择下拉菜单时清除状态
【发布时间】:2021-09-04 05:30:07
【问题描述】:

对 React 完全陌生,我正在构建一个基于 Pokeapi 的小型 Pokedex。我能够获取 Pokemon 及其相应的数据,并成功渲染它。

我有一个下拉菜单,用户可以在其中选择口袋妖怪范围(开始和结束编号),口袋妖怪列表应该会自动更新。问题是,先前的范围没有被清除,并且当前范围与先前的范围相加。但是当我允许一个范围内的所有口袋妖怪完全加载并选择第二个范围时,我没有遇到这个错误。在范围之间快速切换会导致此错误。代码如下:sn-ps。

当我选择一个下拉项时,所有Pokemons 都被设置为空,但渲染中并没有反映出来

GIF 演示我的问题:Pokedex error

代码沙盒链接:here

状态:

constructor(props) {
        super(props);
        this.state = {
            allPokemons: [],    
            limit: 151,
            offset: 0,
            regions: [
                {
                 name: "Kanto",
                 limit: 151,
                 offset: 0,
                },
                {
                 name: "Johto",
                 limit: 100,
                 offset: 151,
                },
                ]      
        }
}

获取口袋妖怪列表及对应数据:

getAllPokemons = async () => {
    const response = await axios.get(`https://pokeapi.co/api/v2/pokemon?limit=${this.state.limit}&offset=${this.state.offset}`).catch((err) => console.log("Error:", err));
    this.getPokemonData(response.data.results);

}

getPokemonData = async (result) => {

    this.setState({
        allPokemons : [],
    })

    var response;
    for (var i = 0; i < result.length; i++) {
        response = await axios.get(`https://pokeapi.co/api/v2/pokemon/${result[i].name}`).catch((err) => console.log("Error:", err));            
        this.setState({
            allPokemons: [...this.state.allPokemons,response.data],               
        })
    }       
}

下拉句柄更改功能

handleChangeRegions = (event) => {

    this.setState({
        allPokemons : [],
    })

    for (var i = 0; i < this.state.regions.length; i++) {
        if (this.state.regions[i].name === event.target.value) {
            this.setState({
                limit : this.state.regions[i].limit,
                offset : this.state.regions[i].offset,
                allPokemons : [],
            },()=>{
                this.getAllPokemons();  
            })

            break;
        }
    }
 }

渲染组件

Object.keys(this.state.allPokemons).map((item, index) =>
<Pokemon
    key={index}
    id={this.state.allPokemons[item].id}
    name={this.state.allPokemons[item].name}
    type={this.state.allPokemons[item].types}
/>
)

下拉组件

<select value={this.state.valueregion} onChange={this.handleChangeRegions}>
{this.state.regions.map((region) => (
    <option value={region.name}>{region.name}&nbsp;({region.offset + 1}-{region.limit + region.offset})</option>
))}
</select>

我需要知道这个问题的原因,非常感谢您的解决方案!

【问题讨论】:

  • 您已将选择值设置为 this.state.valueregion,但未在构造函数中设置;那应该是什么?无论如何,如果您制作一个可重现的 sn-p 并在完成后 ping 我,我可以更深入地了解并找出罪魁祸首
  • @ale917k,我添加了一个codeandbox sn-p,供您参考

标签: javascript reactjs react-component react-state react-state-management


【解决方案1】:

还有一些笔记,

  1. 在您命名的Render Component 中,将键设置为数组的索引是一种非常糟糕的做法,这将导致渲染项目出现问题,特别是 onclick 处理程序等,请使用返回的唯一 ID来自 api 响应,而不是当您在 id 中使用它时(不知道您为什么使用 id 但您需要设置密钥),更多信息here
  2. 您正在使用setState 很多,在handleChangeRegions 中重置allPokemons 键的状态,然后使用下拉列表中的值再次设置它,而您可以将下拉列表中的值传递到下一个函数,它将执行 api 调用,您只需要在屏幕上发生更改的内容时使用状态
  3. 此外,您每次都使用新响应设置状态,导致不必要的重新渲染,只需将 api 响应中的内容保存在数组中,然后在所有请求都通过后将其传递给状态李>

这可能不是解决方案,但它至少应该给你一些提示来缩小问题的范围。如果您可以在代码沙箱中重新生成代码,这将非常有助于找出问题而不是完整代码,但您可以替换 Pokemon 组件,例如显示 id 以方便我们调试代码。

编辑

由于问题现已更新并且原始问题已解决,我检查了您的沙箱,您正在发出单独的请求,每个请求都在等待之前的请求

for (var i = 0; i < result.length; i++) {
  response = await axios
    .get(`https://pokeapi.co/api/v2/pokemon/${result[i].name}`)
    .catch((err) => console.log("Error:", err));
  pokemonArr.push(response.data);
}

这就是你的罪魁祸首,每个请求都被发送,然后你正在等待为每个口袋妖怪处理该请求。你基本上是发送 200 个请求,但不是并行的,而是按顺序发送的,因为你使用的是异步等待。

将该部分替换为以下内容

await Promise.all(
  result.map(pokemonItem => {
    return axios.get(`https://pokeapi.co/api/v2/pokemon/${pokemonItem.name}`)
      .then(result => {
        pokemonArr.push(result.data);
      });
  })
);
this.setState({
  allPokemons:pokemonArr
})

Promise.all() 将所有请求一起发送并与await 之前的语句一起处理它们的响应,直到所有请求完成后再设置状态,瞧!像魅力一样工作。

现在这里还有几个 cmets:

  1. 通常你在componentDidMount()生命周期钩子而不是comopnentWillMount()中发送api调用
  2. 但我想你已经知道,发送 200 个请求来访问每个口袋妖怪的数据并将它们显示在列表中对于后端服务来说是一个糟糕的设计。我知道这不是你的,但像这样的案例你赢了在现实生活中通常不会见面。

你现在唯一可能觉得奇怪的是你的列表不会被排序..因为很多请求是并行发送的,我们不知道哪个请求将首先处理..一个简单的排序函数可以解决这个问题你可以找到一个here

我已经用有效的解决方案 here 更新了你的代码@黑客快乐,欢迎来到 SO!

【讨论】:

  • 非常感谢您的澄清。我现在设置了唯一键,在handleChangeRegions中去掉了setState,得到响应后只设置一次状态。现在它按预期工作,但渲染太慢,所有元素一次渲染,在项目渲染之前我无法选择下拉菜单。添加codeandbox sn-p供您参考here
  • @ramuk 非常感谢您提供沙盒,我现在用一个可行的解决方案更新了答案。
  • 也添加了排序功能,现在它可以按预期工作了。完美的。非常感谢!抱歉,我的声誉不足以支持您的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-10
  • 2019-08-06
  • 2015-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多