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

React路由问题:点击Bootstrap卡片图片跳转至帖子详情页

解决Bootstrap卡片点击跳转详情页并获取帖子ID的问题

1. 先配置路由

首先确保你装了react-router-dom,没装的话执行:

npm install react-router-dom

然后在路由配置文件(比如App.js)里添加详情页的路由规则,带上:id参数:

import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import { Activities } from './path/to/activities';
import Detail from './path/to/detail';

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<Activities />} />
        {/* 配置带id参数的详情页路由 */}
        <Route path="/activity/:id" element={<Detail />} />
      </Routes>
    </Router>
  );
}

export default App;

2. 给卡片图片加跳转逻辑

修改activities.js,引入Link组件,把图片包裹进去,跳转路径带上当前帖子的唯一ID(如果你的帖子用name当唯一标识,就替换成activity.name):

import React from 'react'
import Card from 'react-bootstrap/Card';
import { Link } from 'react-router-dom'; // 新增引入
import "bootstrap/dist/css/bootstrap.min.css";

export const Activities = ({ activityListings, loading }) => {
  if (loading) {
    return <h1>Loading...</h1>;
  }
  return (
    <div className="activities-container">
      {activityListings.map(activity => { 
        let description = activity.blurbs[1].value;
        if (description.split(' ')[0] === "-") {
          description = description.replace('-', '');
        }
        return (
          <Card key={activity.id}> {/* 把key换成唯一id,避免重复渲染问题 */}
            <Card.Body>
              {/* 用Link包裹图片,点击跳转到对应详情页 */}
              <Link to={`/activity/${activity.id}`}>
                <Card.Img variant="top" src={activity.images[0]} style={{cursor: 'pointer'}} />
              </Link>
              <Card.Title>{activity.name}</Card.Title>
              <Card.Subtitle className="mb-2 text-muted">
                {description.split(' ').slice(0, 10).join(' ') + " ..."}
              </Card.Subtitle>
              <span className="rating">
                <i className="fa fa-star"></i>
                {Math.round(activity.reviewMeta?.avgRating * 100) / 100}
              </span>                 
              <br />
              <Card.Text className="card-location">
                {activity.primaryRegion?.name}
              </Card.Text>
            </Card.Body>
          </Card>
        )
      })}
  </div>
  )
}

如果需要先执行某些逻辑再跳转(比如埋点统计),可以用useNavigate替代Link:

import { useNavigate } from 'react-router-dom';

// 组件内部初始化
const navigate = useNavigate();

// 给图片加点击事件
<Card.Img 
  variant="top" 
  src={activity.images[0]} 
  style={{cursor: 'pointer'}}
  onClick={() => {
    // 这里加前置逻辑,比如console.log('点击了帖子:', activity.id)
    navigate(`/activity/${activity.id}`);
  }}
/>

3. 在Detail组件中获取ID并展示详情

用useParams钩子拿到路由里的id,然后根据ID找到对应帖子数据(可以通过props传整个列表,或者发起API请求获取单条数据):

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

const Detail = ({ activityListings }) => {
  const { id } = useParams();
  // 根据id筛选出对应帖子
  const activity = activityListings.find(item => item.id === id);

  if (!activity) {
    return <h1>帖子不存在</h1>;
  }

  return (
    <div className="detail-container">
      <h1>{activity.name}</h1>
      <img src={activity.images[0]} alt={activity.name} style={{width: '100%'}} />
      <p>{activity.blurbs[1].value}</p>
      <p>评分:{Math.round(activity.reviewMeta?.avgRating * 100) / 100}</p>
      <p>地区:{activity.primaryRegion?.name}</p>
      {/* 这里添加更多详情内容 */}
    </div>
  );
};

export default Detail;

如果是通过API获取单条数据,用useEffect发起请求:

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

const Detail = () => {
  const { id } = useParams();
  const [activity, setActivity] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // 替换成你的实际API地址
    fetch(`/api/activities/${id}`)
      .then(res => res.json())
      .then(data => {
        setActivity(data);
        setLoading(false);
      })
      .catch(err => {
        console.error('获取详情失败:', err);
        setLoading(false);
      });
  }, [id]);

  if (loading) {
    return <h1>Loading...</h1>;
  }

  if (!activity) {
    return <h1>帖子不存在</h1>;
  }

  return (
    <div className="detail-container">
      <h1>{activity.name}</h1>
      <img src={activity.images[0]} alt={activity.name} style={{width: '100%'}} />
      <p>{activity.blurbs[1].value}</p>
      <p>评分:{Math.round(activity.reviewMeta?.avgRating * 100) / 100}</p>
      <p>地区:{activity.primaryRegion?.name}</p>
    </div>
  );
};

export default Detail;

注意事项

  • 路由参数名要和useParams里取的一致,比如路由是:id,就用const { id } = useParams();如果用name当标识,路由改成/activity/:name,然后取const { name } = useParams()。
  • 卡片的key一定要用唯一值(比如id),不要用name,避免重复数据导致React渲染异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 03:30:51