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
相关产品推荐
相关产品推荐

