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

如何使用React Hooks和useParams实现点击卡片跳转对应详情页功能

具体实现指导

先修复现有代码的潜在bug

EventList.js中posts的初始值为空字符串,应该改为空数组,避免后续列表判断逻辑异常:

// 替换原来的useState定义
const [posts, setPosts] = useState([]);

步骤1:调整路由与跳转逻辑

(可选优化)避免标题特殊字符导致路由失效

标题可能包含空格、特殊符号,跳转时建议对标题做编码处理,修改Event.js中的Link组件:

<Link to={`/${encodeURIComponent(post.title)}`}>
  <button className={styles.btns}>查看详情</button>
</Link>

如果你的post数据有唯一id,更推荐用id作为路由参数,匹配准确性更高:

  • Event.js跳转改为:to={/event/${post.id}}
  • App.js对应路由改为:<Route path="/event/:postId" exact children={<EventDetails />}></Route>

步骤2:修改EventDetails.js用useParams实现数据匹配

以下是完整的修改后代码,通过useParams获取路由参数,拉取数据后匹配对应帖子详情:

import React, { useState, useEffect } from "react";
import Navbar from "../Navbar/Navbar";
import styles from "./EventDetails.module.css";
import "bootstrap/dist/css/bootstrap.min.css";
import { Link, useParams } from "react-router-dom";
import axios from "axios";

// 替换为你自己的接口配置
let config = { Authorization: "3055f8f90fa44bbe8bda05385a20690a" };
const baseurl = "https://newsapi.org/v2/top-headlines?sources=bbc-news";

const EventDetails = () => {
  // 从路由中获取参数,注意参数名要和App.js路由中定义的一致
  const { title } = useParams();
  const [currentPost, setCurrentPost] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // 解码路由中的标题参数
    const decodedTitle = decodeURIComponent(title);
    // 拉取新闻列表匹配对应帖子
    axios
      .get(baseurl, { headers: config })
      .then((response) => {
        const allPosts = response.data.articles;
        // 匹配标题一致的帖子
        const target = allPosts.find(post => post.title === decodedTitle);
        setCurrentPost(target);
      })
      .catch((error) => console.error(`请求错误: ${error}`))
      .finally(() => setLoading(false));
  }, [title]);

  // 异常状态处理
  if (loading) return <div style={{padding: '20px', textAlign: 'center'}}>加载中...</div>;
  if (!currentPost) return <div style={{padding: '20px', textAlign: 'center'}}>未找到对应帖子</div>;

  return (
    <div>
      <Navbar />
      <div className={styles.eventBg}>
        <div className="container">
          <div>
            <img
              src={currentPost.urlToImage}
              alt={currentPost.title}
              width="100%"
              className={styles.heroEventImage}
            />
          </div>
          <div className={styles.bookingDetails}>
            <div className={styles.nameBook}>
              <div>
                <div className={styles.eventNameHeader}>
                  <h1 className={styles.eventName}>{currentPost.title}</h1>
                </div>
                <div className={styles.genre}>
                  <div className={styles.genreText}>作者:{currentPost.author}</div>
                </div>
                <div style={{margin: '20px 0'}}>
                  {currentPost.content}
                </div>
              </div>
              <div className={styles.bookingBtn}>
                <div className={styles.booking}>
                  <Link to="/GeneralBooking">
                    <button
                      className={styles.bookBtn}
                      style={{ height: "60px", fontSize: "18px" }}
                    >
                      Book
                    </button>
                  </Link>
                </div>
              </div>
            </div>
            <div className={styles.venueTime}>
              <div className={styles.dateTime}>
                <div className={styles.dateTimeText}>发布时间:{new Date(currentPost.publishedAt).toLocaleDateString()}</div>
                <div className={styles.price}>来源:{currentPost.source.name}</div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

export default EventDetails;

可选优化:减少重复请求

每次进入详情页都拉取全量列表会浪费请求资源,可以在列表页拉取数据时缓存到本地,详情页优先读缓存:

  1. 在EventList.js的AllPosts方法中添加缓存逻辑:
.then((response) => {
  const allPosts = response.data.articles;
  setPosts(allPosts);
  // 新增缓存到本地存储
  localStorage.setItem('postList', JSON.stringify(allPosts));
})
  1. 在EventDetails.js的useEffect中优先读缓存:
useEffect(() => {
  const decodedTitle = decodeURIComponent(title);
  // 先读本地缓存
  const localList = localStorage.getItem('postList');
  if (localList) {
    const allPosts = JSON.parse(localList);
    const target = allPosts.find(post => post.title === decodedTitle);
    setCurrentPost(target);
    setLoading(false);
    return;
  }
  // 缓存不存在再发请求
  axios.get(baseurl, { headers: config })
    // 原有请求逻辑不变
}, [title])

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.18 17:06:05