React 18 useEffect搭配axios请求触发无限循环问题求助
React 18 调用TMDB接口setState触发无限循环问题修复
问题根因
无限循环的核心触发点是useEffect依赖数组配置逻辑错误,形成了闭环触发链:
- 组件首次渲染时,绑定在
useEffect里的接口请求逻辑执行,请求成功后调用setMovieList更新movieList状态 - 你在负责拉取电影列表的
useEffect依赖数组中加入了movieList,状态更新触发组件重渲染时,React检测到依赖项变化,会重新执行effect内的全部逻辑 - effect重新执行后再次发起接口请求、再次调用
setMovieList更新状态,整个流程无限循环,最终表现为请求不停发、控制台无限打印返回结果
另外代码里还存在几个不影响循环但会导致异常的小问题:
- 异步写法混用
async/await和.then链,逻辑冗余且容易出错 - TMDB接口的page参数写为
1p属于笔误,正确参数应为page=1 setMovieList之后立刻执行console.log(movieList)无法拿到最新状态值,React的setState是异步批处理机制,更新后的值要到下一次渲染周期才能获取到
修复方案
- 调整拉取列表的useEffect依赖:首次挂载拉取一次全量列表的场景下,依赖数组设为空数组
[],表示仅在组件挂载时执行一次effect,从根源切断循环触发链 - 统一异步请求写法,修正接口参数笔误,增加请求错误捕获逻辑
- 如果需要查看更新后的movieList值,单独加一个依赖movieList的effect专门打印日志,不要在更新状态的同一步骤同步打印
修复后完整代码
import { useEffect, useState } from "react" import { useNavigate } from "react-router-dom" import axios from 'axios' function Listado() { const [movieList, setMovieList] = useState([]) const navigate = useNavigate() // 登录鉴权逻辑 useEffect(() => { const token = localStorage.getItem('token') console.log(token) if (token == null) { navigate('/') } }, [navigate]) // 首次挂载拉取电影列表 useEffect(() => { const apiKey = 'b34999ac538aed71a19355d996f1081f' const fetchMovieList = async () => { try { const response = await axios.get(`https://api.themoviedb.org/3/discover/movie`, { params: { api_key: apiKey, language: 'es-ES', page: 1 } }) setMovieList(response.data.results) } catch (err) { console.error('拉取电影列表失败:', err) } } fetchMovieList() }, []) // 空数组表示仅挂载时执行一次 // 单独监听movieList变化打印最新值 useEffect(() => { console.log('最新电影列表:', movieList) }, [movieList]) return ( <> {/* 列表渲染逻辑 */} <div className='col3' style={{ border: '1px solid red' }}>Peli 1</div> </>) } export default Listado
补充说明:如果后续需要做分页、关键词搜索等触发重新拉取列表的功能,只需要把页码、搜索关键词这类触发请求变化的变量加入拉取列表的useEffect依赖数组即可,永远不要把当前effect内会更新的状态直接加入依赖(除非加了新旧值对比的判断,值完全相等时不执行setState)
内容的提问来源于stack exchange,提问作者Jose Antonio Miro Erdmann
相关产品推荐
相关产品推荐

