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

React项目中uuid生成ID后useParams匹配详情数据失效问题解决

问题描述

我基于API搭建了一个新闻项目,可通过分类切换获取对应数据。点击新闻卡片进入详情页时,因API返回数据无ID字段,我使用uuid生成ID,期望通过useParams获取ID并匹配对应详情数据,但该功能无法正常工作,请问如何解决?

相关组件代码

NewsDetail组件

import React, { useState, useEffect } from 'react'
import { useParams } from 'react-router-dom'

const NewsDetail = ({ state }) => {
  const { id } = useParams();

  return (
    <div>
      {
        state
          .filter((a) => a.id === id)
          .map((card, index) => (
            <>
              <div className="card" key={index}>
                <h2>{card.title}</h2>
                <h2>{card.content}</h2>
                <img src={card.imageUrl} alt="" />
              </div>
            </>
          ))
      }
    </div>
  )
}

export default NewsDetail

NewsItem组件

import React from 'react'
import clock from "../components/assets/img/Clock.svg"
import user from "../components/assets/img/User.svg"
import { Link } from 'react-router-dom'

const NewsItem = (props) => {
  const { imageUrl, title, author, content, date, id } = props

  return (
    <Link className="col-lg-4 p-2" to={`/detail/${id}`}>
      <div className="newsItem">
        <img src={imageUrl} alt='newsPhoto' />
        <h2>{id}</h2>
        <div className="itemBody">
          <p className='title'>{title}</p>
          <div className="line"></div>
          <p className='content'>{content}</p>
          <div className="itemfooter">
            <span><img src={clock} alt='clock' />{date}</span>
            <span><img src={user} alt='user' />{author}</span>
          </div>
        </div>
      </div>
    </Link>
  )
}

export default NewsItem

Home组件

import React, { useEffect, useState } from "react";
import NewsItem from "./NewsItem";
import SpinnerLoad from "./SpinnerLoad";
import { v4 as uuidv4 } from 'uuid';

const Home = (props) => {
  const Category = [
    "all",
    "business",
    "sports",
    "world",
    "technology",
    "entertainment",
    "science"
  ];
  const { state, setState} = props;
  const [loading, setLoading] = useState(false)

  const fetchValue = (category) => {
    fetch(`https://inshorts-api.herokuapp.com/news?category=${category}`)
      .then(res => res.json())
      .then(res => {
        setState(res.data)
        setLoading(true)
      })
      .catch((error) => console.log(error))
      console.log(state);
      setLoading(false);
  };

  // const fetchValue = async () => {
  //   try {
  //     const data = await axios
  //       .get(`https://inshorts-api.herokuapp.com/news?category=sports`)
  //       .then(res => {
  //         console.log(res);
  //         setState(res.data)
  //       })
  //     setLoading(true)
  //     console.log(loading);
  //   } catch (e) {
  //     console.log(e);
  //   }
  // }

  const CategoryButton = ({ category }) => (
    <button onClick={() => fetchValue(category)} style={{ textTransform: 'capitalize' }}>{category}</button>
  );

  useEffect(() => {
    fetchValue('all')
  },[])

  return (
    <>
      <div className="header-bg">
        <h1 className="mb-3">News</h1>
        <div className="btns ">
          {Category.map((value, index) => {
            return <CategoryButton category={value} key={index} />;
          })}
        </div>
      </div>

      <div className="news">
        <div className="container">
          <div className="row">
            { 
            !loading 
            ? <SpinnerLoad/>
             :
            state.map((data,index) => {
              return (
                <NewsItem
                  imageUrl={data.imageUrl}
                  author={data.author}
                  title={data.title}
                  content={data.content}
                  date={data.date}
                  id={uuidv4()}
                  key={index}
                />
              );
            })
            }
          </div>
        </div>
      </div>
    </>
  );
};

export default Home;
解决方案

核心问题是:你在Home组件里给NewsItem临时生成的uuid并没有存入到state的新闻数据中,导致详情页无法通过id匹配到对应数据。按以下步骤修改:

1. 在获取API数据时给每条新闻添加uuid

修改Home组件的fetchValue方法,在保存数据到state前,给每条新闻添加唯一id,同时修正loading状态的逻辑错误:

const fetchValue = (category) => {
  setLoading(true); // 请求开始时标记加载中
  fetch(`https://inshorts-api.herokuapp.com/news?category=${category}`)
    .then(res => res.json())
    .then(res => {
      // 给每条新闻添加uuid字段
      const newsWithId = res.data.map(item => ({
        ...item,
        id: uuidv4()
      }));
      setState(newsWithId);
    })
    .catch(error => console.log(error))
    .finally(() => {
      setLoading(false); // 请求完成后关闭加载状态
    });
};

2. 修改Home组件中NewsItem的传参

现在state里的每条新闻都自带id了,直接传入数据中的id即可,同时用id作为key(比index更稳定):

state.map((data) => {
  return (
    <NewsItem
      imageUrl={data.imageUrl}
      author={data.author}
      title={data.title}
      content={data.content}
      date={data.date}
      id={data.id} // 使用数据自带的id
      key={data.id} // 用唯一id作为key
    />
  );
})

3. 优化NewsDetail组件(可选)

用find代替filter+map,因为我们只需要匹配单条数据,同时处理新闻不存在的情况:

import React from 'react'
import { useParams } from 'react-router-dom'

const NewsDetail = ({ state }) => {
  const { id } = useParams();
  const news = state.find(a => a.id === id);

  if (!news) {
    return <div>该新闻不存在</div>;
  }

  return (
    <div className="card">
      <h2>{news.title}</h2>
      <h2>{news.content}</h2>
      <img src={news.imageUrl} alt={news.title} />
    </div>
  )
}

export default NewsDetail

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 17:36:15