React中useState变量nextToken在fetch请求成功后未更新
解决React中useState异步更新导致分页token无法拼接的问题
你的代码里有两个核心问题,导致nextToken始终没法正确拼接到请求URL中:
- React状态更新是异步的:调用
setNextToken(json.nextPageToken)后,nextToken不会立刻变成新值,所以你紧接着console.log(nextToken)打印的还是初始的null——这是React的正常机制,不是代码bug。 - 缺少触发下一页请求的逻辑:当前代码只在组件挂载时调用一次
getVideos,哪怕nextToken被更新成了有效值,也不会自动发起下一页请求;就算你手动触发加载,也可能因为没拿到最新状态值导致URL拼接失败。
修复后的完整代码
import { useCallback, useEffect, useState } from "react"; // 替换成你的实际接口地址 const API_URL = "https://example.com/api/videos"; const VideoList = () => { const [isLoading, setIsLoading] = useState(false); const [videos, setVideos] = useState([]); const [nextToken, setNextToken] = useState(null); // 用useCallback包裹,确保每次状态更新时函数能拿到最新的nextToken const getVideos = useCallback(async () => { if (isLoading) return; // 防止重复触发请求 setIsLoading(true); try { // 这里会使用最新的nextToken拼接URL const url = nextToken ? `${API_URL}&token=${nextToken}` : API_URL; console.log("Fetching data from:", url); const data = await fetch(url); if (!data.ok) throw new Error("请求数据失败"); const json = await data.json(); setNextToken(json.nextPageToken); // 合并新数据到现有列表 setVideos(prev => [...prev, ...json.items]); } catch (error) { console.error("加载视频出错:", error); } finally { setIsLoading(false); } }, [nextToken, isLoading]); // 组件挂载时加载第一页 useEffect(() => { getVideos(); }, [getVideos]); // 渲染视频列表和加载更多按钮 return ( <div> <div className="video-list"> {videos.map(video => ( <div key={video.id} className="video-item"> {video.title} </div> ))} </div> {/* 有下一页token且未加载时显示加载按钮 */} {nextToken && !isLoading && ( <button onClick={getVideos}>加载更多</button> )} {isLoading && <p>加载中...</p>} </div> ); }; export default VideoList;
关键修复说明
- 用
useCallback包裹请求函数:把nextToken和isLoading加入依赖数组,确保每次这两个状态更新时,getVideos函数都会拿到最新的值,避免闭包导致的旧状态问题。 - 添加重复请求拦截:通过
isLoading状态判断,防止用户多次点击加载按钮导致重复请求。 - 正确监听状态变化:如果要查看更新后的
nextToken,不要在setNextToken后立刻打印,而是添加一个单独的useEffect监听:
useEffect(() => { console.log("当前分页token:", nextToken); }, [nextToken]);
内容的提问来源于stack exchange,提问作者Vishal Tanna
相关产品推荐
相关产品推荐

