You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;

修复后流程说明

  1. 首页传递storyId给Story组件,直接用该ID构建跳转链接
  2. 详情页通过useParams读取URL中的ID参数
  3. StorySingular组件校验ID有效性后,请求对应ID的Story数据

内容的提问来源于stack exchange,提问作者Rose

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 14:30:52