React使用SWR实现点击按需请求数据缓存时首次赋值异常如何解决
问题根源
setState本身是异步批量更新的,你在handleTv中同步调用setShouldFetchTv、setOnTv、setMedia时,更新的状态不会立刻生效,本次函数执行时拿到的还是旧的状态值- SWR的请求是异步的,触发
shouldFetchTv变为true后,请求不会立刻返回结果,tvResult在第一次点击时还是初始的undefined - 你不需要自己实现缓存逻辑,SWR天然支持同key请求缓存,只要请求地址不变,第一次请求后后续都会直接读取缓存,不会重复发起请求,完全匹配你的需求
优化实现方案
你可以直接用一个状态记录当前激活的标签,对应触发对应SWR请求即可,代码简化如下:
import useSWR from 'swr' import React, { useState } from "react"; const fetcher = async (url) => { const res = await fetch(url); if (!res.ok) throw new Error('请求失败') return res.json() }; const Trending = ({ data: streamingData }) => { // 记录当前激活的标签,默认是streaming const [activeTab, setActiveTab] = useState('streaming') const urls = { onTv: `https://api.themoviedb.org/3/tv/on_the_air?api_key=${process.env.NEXT_PUBLIC_API_KEY}&language=en-US&page=1`, inTheaters: `https://api.themoviedb.org/3/movie/now_playing?api_key=${process.env.NEXT_PUBLIC_API_KEY}&language=en-US&page=1®ion=US` } // 只有激活onTv标签时才发起请求,SWR自动缓存结果 const { data: onTvData } = useSWR(activeTab === 'onTv' ? urls.onTv : null, fetcher) // 只有激活inTheaters标签时才发起请求 const { data: inTheatersData } = useSWR(activeTab === 'inTheaters' ? urls.inTheaters : null, fetcher) // 根据当前激活标签返回对应展示数据 const currentMedia = { streaming: streamingData, onTv: onTvData, inTheaters: inTheatersData }[activeTab] return ( <div> {/* 标签栏 */} <div onClick={() => setActiveTab('streaming')}> <h1>Streaming</h1> </div> <div onClick={() => setActiveTab('onTv')}> <h1>On Tv</h1> </div> <div onClick={() => setActiveTab('inTheaters')}> <h1>In Theaters</h1> </div> {/* 数据展示区域,可自定义loading、错误态逻辑 */} {currentMedia ? ( <div> {/* 渲染你的媒体列表数据 */} </div> ) : <div>加载中...</div>} </div> ) }
逻辑说明
- 当第一次点击
On Tv标签时,activeTab变为onTv,SWR检测到请求key存在就会发起请求,请求完成后自动更新onTvData,页面自动渲染对应内容 - 后续再切换到其他标签再切回
On Tv时,SWR会直接读取之前缓存的结果,不会重复发起请求 - 不需要自己维护缓存、是否请求的状态,全部交给SWR处理,逻辑更简洁也不会出现异步状态更新的问题
内容的提问来源于stack exchange,提问作者LeoM
相关产品推荐
相关产品推荐

