Next JS结合SWR实现加载更多按钮后接口不触发如何解决
问题根源
- SWR 以第一个参数的缓存 key 来判断是否需要重新发起请求,你当前固定写死了
'locations'作为 key,即使pageIndex和dataCount变化,SWR 也会认为是同一个请求,直接复用旧缓存,不会触发新请求。 - 请求 URL 用了单引号包裹,没有用模板字符串的反引号
`,导致pageIndex和dataCount变量不会被正确解析,永远是字符串原值。 - 当前你分页的逻辑是加载下一页替换原有数据,如果你要做「加载更多」追加数据的效果,还需要调整数据合并逻辑。
- 额外的小问题:axios 本身返回的
response.data已经是 JS 对象,不需要再加await,你的 fetcher 里多写了冗余逻辑。
修复步骤
- 修改 SWR key,关联分页参数,把 key 改成包含
pageIndex和dataCount的数组,只要这两个参数变化,SWR 就会自动发起新请求。 - 修正 URL 模板字符串的包裹符号,把单引号换成反引号。
- 调整加载更多逻辑为数据追加,保留之前加载的列表数据。
- 拆分初始加载和加载更多的状态逻辑,避免状态混乱。
修复后完整代码
import useSWR from 'swr' import axios from 'axios' import { useState, useCallback } from 'react' //... other dependencies import export default function Locations({...props}) { // 存储所有已加载的列表数据 const [allLocations, setAllLocations] = useState([]) const [loading, setLoading] = useState(true) // 加载更多按钮的独立加载状态 const [loadMoreLoading, setLoadMoreLoading] = useState(false) const [dataCount] = useState(3); const [pageIndex, setPageIndex] = useState(1) const locationsFetcher = async([key, page, limit]) => { // 用反引号包裹模板字符串 const response = await axios(`${process.env.url}?page=${page}&limit=${limit}`, {headers:{}}) return response.data.results; } const {data, error} = useSWR(['locations', pageIndex, dataCount], locationsFetcher,{ onErrorRetry: (error, key, config, revalidate, { retryCount }) => { if (error.status === 404) return if (retryCount >= 10) return setTimeout(() => revalidate({ retryCount }), 5000) }, // 数据请求成功后合并到已有列表 onSuccess: (newData) => { setLoading(false) setLoadMoreLoading(false) // 如果是第一页就直接赋值,后续页追加到现有列表末尾 if(pageIndex === 1) { setAllLocations(newData) } else { setAllLocations(prev => [...prev, ...newData]) } } }) const loadMore = useCallback(() => { setLoadMoreLoading(true) setPageIndex(prev => prev + 1) }, []) return ( <> <table> {error && <tr><td><p>加载数据出错</p></td></tr>} {loading ? <tr><td colSpan="6"><p>加载中...</p></td></tr> : allLocations.length > 0 ? (allLocations.map((location, index) => ( <tr index={index} key={index}> <td>{location.name}</td> {/* 其他字段渲染逻辑保持不变 */} <td>{location.phone}</td> </tr> ))) : (<tr><td><NoDataFound /></td></tr>)} </table> <div className="click_btn"> <button onClick={loadMore} disabled={loadMoreLoading}> <span>{loadMoreLoading ? '加载中...' : '展开更多'}</span> </button> </div> </> ) }
内容的提问来源于stack exchange,提问作者Deep Kakkar
相关产品推荐
相关产品推荐

