You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Axios无法取消多请求导致宝可梦搜索时组件重复渲染、结果重复问题

问题根因

出现重复结果、渲染次数累加的核心原因有两个:

  • 取消请求的source实例放在组件顶层定义,每次组件渲染都会生成新的实例,导致useEffect的清理函数无法正确取消上一轮未完成的请求
  • 每次pokeInput变化触发useEffect执行时,你没有清空之前的pokemons数组,直接往旧数组里追加新请求返回的数据,搜索次数越多数组里的重复条目就越多

修复后的代码

import { useState, useEffect } from 'react'
import axios from 'axios';
import Pokemon from './pokemon';
import { FaSearch } from 'react-icons/fa'

function App() {
  const [pokemons, setPokemons] = useState([])
  const [pokeInput, setPokeInput] = useState('')

  useEffect(() => {
    const cancelToken = axios.CancelToken
    const source = cancelToken.source()
    // 每次发起新请求前先清空旧列表
    setPokemons([])
    for (let i = 1; i < 10; i++) {
      axios.get(`https://pokeapi.co/api/v2/pokemon/${i}`, {
        cancelToken: source.token
      })
        .then(res => {
          setPokemons((poke) => {
            return [...poke, res.data]
          })
        })
        .catch(err => {
          // 忽略取消请求的报错
          if (axios.isCancel(err)) return
          console.log(err)
        })
    }
    return () => source.cancel()
  }, [pokeInput])

  const pokeSort = pokemons.filter((pokemon) => {
    return pokemon.name.toLowerCase().includes(pokeInput.toLowerCase())
  })

  let pokeInputChange = (e) => {
    setPokeInput(e.target.value)
  }
  // 阻止表单默认提交刷新页面的行为
  const handleSubmit = (e) => {
    e.preventDefault()
  }

  return (
    <div className="App">
      <form className='search' onSubmit={handleSubmit}>
        <h1>Search Pokemon</h1>
        <div className='form'>
          <input
            onChange={pokeInputChange}
            type="text"
            placeholder='Search Pokemon'
            id="pokeSearchBar"
            className='searchbar'
          />
          <span className='search_icon'><FaSearch /></span>
          <div className="extra1"></div>
          <div className="extra2"></div>
          <button className='go'>GO</button>
        </div>
      </form>

      {
        pokeSort.map((pokemon, index) => {
          console.log(pokemons)
          return (
            <Pokemon
              key={index}
              name={pokemon.name}
              type={pokemon.types}
              moves={pokemon.moves}
              height={pokemon.height}
              weight={pokemon.weight}
              front_image={pokemon.sprites.front_default}
              back_image={pokemon.sprites.back_default}
            />
          )
        })
      }
    </div>
  );
}

export default App;

修改说明

  • 把cancelToken和source的创建移到useEffect内部,保证每次清理函数取消的都是当前这一轮发起的请求
  • 每次useEffect执行开头先清空pokemons数组,避免旧数据残留导致重复
  • catch里加了取消请求的判断,避免取消请求的报错打印到控制台
  • 给表单加了阻止默认提交的逻辑,避免点GO按钮刷新页面

内容的提问来源于stack exchange,提问作者Lucky Jain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 21:06:03