React路由跳转时Story ID传递失败,请求排查解决
问题:点击Story跳转详情页后请求
undefined.json,无法获取对应ID的资源 核心问题分析
点击首页Story组件跳转到详情页后,请求的是undefined.json,根源在于跳转链接传递ID错误+详情页未正确读取URL中的ID参数,同时组件的异步逻辑存在依赖缺失问题。
具体错误与修复方案
1. Story组件:跳转链接传递ID错误
当前代码依赖异步获取的story.id构建链接,但story初始为空对象,首次渲染时id为undefined;同时state里传递的是字符串'id'而非变量。
修复代码:
直接使用props传入的storyId(首页已拿到该ID,无需等待异步请求):
/* eslint-disable react-hooks/exhaustive-deps */ import React, { useState, useEffect} from 'react'; import { getStory } from '../services/hnApi'; import { Card, Container, Nav } from 'react-bootstrap' import { mapTime } from '../mappers/mapTime'; import { Link } from 'react-router-dom'; export const Story = ({storyId}) => { const[story, setStory] = useState({}); // 优化定时器:刷新数据而非整个页面 useEffect(() => { const timer = setTimeout(() => { getStory(storyId).then((data) => data.url && setStory(data)); }, 60000); return () => clearTimeout(timer); }, [storyId]); useEffect(() => { getStory(storyId).then((data) => data.url && setStory(data)) }, [storyId]); return story && story.url ? ( <Container data-id={storyId} fluid="xl" style={{marginTop: "1%", marginBottom: "1%"}}> <Nav.Item> <Link to={`/storyPage/${storyId}`} state={{ id: storyId }} style={{ textDecoration: 'none' }}> <Card style={{ paddingLeft: "1%", paddingTop: "1%", paddingBottom: "1%"}}> <Card.Title>{story.title}</Card.Title> <br/> <Card.Text style={{color: 'black', fontStyle: 'italic', fontSize: '15px'}}>Author: {story.by}</Card.Text> <Card.Text style={{color: 'black', fontStyle: 'italic', fontSize: '15px'}}>Posted: {mapTime(story.time)}</Card.Text> <Card.Text style={{color: 'black', fontStyle: 'italic', fontSize: '15px'}}>Rating: {story.score}</Card.Text> </Card> </Link> </Nav.Item> </Container> ):null; }; export default Story;
2. StoryPage组件:未读取URL中的ID参数
当前代码重新请求所有Story ID并取第一个,完全忽略了路由中:id参数,导致传递给StorySingular的ID为undefined。
修复代码:
使用useParams钩子获取URL中的ID参数:
import React from 'react'; import { Button, Container } from 'react-bootstrap'; import { ArrowLeft } from 'react-bootstrap-icons'; import { StorySingular } from './StorySingular'; import { useParams } from 'react-router-dom'; export const StoryPage = () => { const { id } = useParams(); // 直接获取路由中的ID参数 return ( <Container key={id}> <Button style={{marginLeft: '1%', marginTop:'1%'}} variant="outline-info" href='/'><ArrowLeft/></Button> <br/> <StorySingular storyId={id} /> </Container> ); }; export default StoryPage;
3. StorySingular组件:依赖缺失与参数校验
当前useEffect依赖为空,且未校验storyId是否存在,会导致初始时请求undefined.json。
修复代码:
添加storyId到依赖数组,并先校验参数有效性:
/* eslint-disable react-hooks/exhaustive-deps */ import React, { useEffect, useState } from 'react'; import { getStory } from '../services/hnApi'; import { Card, Container, Nav } from 'react-bootstrap'; import { Comments } from '../comments/Comments'; import { mapTime } from '../mappers/mapTime'; export const StorySingular = ({ storyId }) => { const [story, setStory] = useState({}); const { kids, id, url } = story; useEffect(() => { if (!storyId) return; // 先校验ID是否存在 getStory(storyId).then((data) => { if (data && data.url) { setStory(data); } }); }, [storyId]); // 添加storyId到依赖数组 return story && url ? ( <> <Container data-id={id}> <Card style={{paddingLeft: "1%", paddingTop: "1%"}}> <Card.Title style={{paddingLeft: "1%"}}>{story.title}</Card.Title> <Nav.Link href={story.url}>{url}</Nav.Link> <br/> <Card.Text style={{color: 'black', fontStyle: 'italic',paddingLeft: "1%", fontSize: '14px'}}>Author: {story.by}</Card.Text> <Card.Text style={{color: 'black', fontStyle: 'italic',paddingLeft: "1%", fontSize: '14px'}}>Posted: {mapTime(story.time)}</Card.Text> <Card.Text style={{color: 'black', fontStyle: 'italic',paddingLeft: "1%", fontSize: '14px'}}>Comments: {story.descendants}</Card.Text> <Card.Text>{kids && <Comments commentIds={kids} root />}</Card.Text> </Card> </Container> </> ): null; }; export default StorySingular;
修复后流程说明
- 首页传递
storyId给Story组件,直接用该ID构建跳转链接 - 详情页通过
useParams读取URL中的ID参数 - StorySingular组件校验ID有效性后,请求对应ID的Story数据
内容的提问来源于stack exchange,提问作者Rose
相关产品推荐
相关产品推荐

