useSWR组件状态未更新至fetcher Promise结果,isLoading状态异常求助
问题
- 组件状态无法更新为fetcher函数返回的Promise解析后的数据
- 初始状态未正确显示
isLoading: true
代码实现
service.js
import axios from 'axios'; export const fetchNewsDetailsById = (newsID) => { console.log('args in fetch news ', newsID) const pr = axios.get('https://swapi.dev/api/people/1') .then(res => res.data) .then(res => { const X = res.data.filter(obj => obj.id == newsID)[0]; console.log('api data ', X); //// THIS X I WANT IN MY COMPONENT return X; }); console.log('my promise ', pr); return pr; }
hooks.js
import useSWR from 'swr' import { fetchNewsDetailsById } from './service'; export const useNewsDetailsBySlug = (newSlug) => { const parts = newSlug.split("-"); const newsId = parts[parts.length - 1]; const { data, error, isLoading } = useSWR ( ['news', newsId], fetchNewsDetailsById(newsId) ); console.log(' news instance in the hook ', data); return { data, isLoading, isError: error } }
NewsDetails.jsx
import React, { useMemo } from 'react' import { useParams } from 'react-router-dom'; import { formatDate } from '../../../helpers/dates'; import { useNewsDetailsBySlug } from './hooks'; const NewsDetails = () => { const { id: slug } = useParams(); const reqObj = useNewsDetailsBySlug(slug); const { data: dataObj, isLoading, isError } = reqObj; console.log(reqObj) if (!isLoading && !dataObj && !isError) { return <h2>No State onlyyy !!</h2>; } if (isLoading) { return <h2>Loading...</h2> } if (isError) { return <h2>Oops !! something went wrong while fetching details of the news</h2> } return ( <div> <h3>{dataObj.title}</h3> </div> ) } export default NewsDetails;
当前状态与日志
当前组件状态始终为:
{data: undefined, isLoading: false, isError: undefined}
控制台日志:
args in fetch news 6 service.js:12 my promise Promise hooks.js:10 news instance in the hook undefined component.jsx:12 {data: undefined, isLoading: false, isError: undefined} service.js:9 api data -- Exact data in want to be in my component
问题排查与解决方案
1. useSWR fetcher参数传递错误
useSWR的第二个参数要求是函数,而非直接调用函数返回的Promise。你当前直接执行fetchNewsDetailsById(newsId),导致组件初始化时就触发请求,且useSWR无法监听Promise状态变化,因此不会更新data和isLoading。
修复后的hooks.js:
import useSWR from 'swr' import { fetchNewsDetailsById } from './service'; export const useNewsDetailsBySlug = (newSlug) => { const parts = newSlug.split("-"); const newsId = parts[parts.length - 1]; // 传递函数,useSWR会自动处理请求生命周期 const { data, error, isLoading } = useSWR ( ['news', newsId], () => fetchNewsDetailsById(newsId) ); console.log(' news instance in the hook ', data); return { data, isLoading, isError: error } }
2. API响应数据处理错误
请求https://swapi.dev/api/people/1返回的结果中没有嵌套的data字段,你直接访问res.data.data会得到undefined,后续filter操作自然无法得到有效数据。另外,swapi的people接口返回数据没有id字段,需要从url字段提取。
修复后的service.js:
import axios from 'axios'; export const fetchNewsDetailsById = (newsID) => { console.log('args in fetch news ', newsID) return axios.get('https://swapi.dev/api/people/1') .then(res => { // swapi返回的res.data就是目标数据,无嵌套data字段 console.log('api raw data ', res.data); // 从url中提取id:例如url为"https://swapi.dev/api/people/1/",提取最后一段数字 const id = res.data.url.split('/').filter(Boolean).pop(); // 匹配传入的newsID,匹配成功返回数据,否则返回null return id === newsID ? res.data : null; }); }
3. 组件逻辑简化
可以移除冗余的条件判断,让代码更清晰:
const NewsDetails = () => { const { id: slug } = useParams(); const { data: dataObj, isLoading, isError } = useNewsDetailsBySlug(slug); if (isLoading) { return <h2>Loading...</h2> } if (isError || !dataObj) { return <h2>{isError ? 'Oops !! something went wrong' : 'No data found'}</h2> } return ( <div> <h3>{dataObj.name}</h3> {/* swapi返回的是name字段,而非title */} </div> ) }
内容的提问来源于stack exchange,提问作者gkd
相关产品推荐
相关产品推荐

