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

React点击动态生成<Link>无法设置blogID渲染博客详情问题

问题原因

你的代码有3个核心错误,导致状态设置不生效、详情页拿不到对应ID:

  • 事件回调逻辑完全写错:你定义的getBlogID没有接收当前点击项的博客ID,执行setBlogID(blogID)等价于把状态当前的旧值(初始是null)重新赋值给状态,相当于没有做任何更新,状态自然永远是null。
  • 状态作用域错误:你在BlogContainer组件里用useState存储的blogID是组件私有本地状态,点击Link跳转到详情页时,列表页组件会被卸载,内部所有state都会被清空销毁。详情页BlogPost从useBlog里取的blogID和列表页的本地state完全是两个独立的存储空间,根本读不到列表页设置的值。
  • 附带隐性bug:BlogPost组件里没有引入blogs变量直接使用会抛引用错误;另外你已经把博客ID拼在了跳转URL里,完全没必要额外存状态传递ID,直接从路由参数取值是React Router的标准实现方式,还能避免刷新页面丢状态的问题。
修复方案(推荐:路由参数传值)

这种方案不需要额外绑定onClick存状态,URL天然携带资源ID,刷新页面、直接输入详情页URL都能正常访问,是单页应用路由跳转的最佳实践。

  1. 先修改路由配置,给详情页路由加参数占位:
// App.jsx 路由配置示例
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import BlogContainer from './pages/BlogContainer';
import BlogPost from './pages/BlogPost';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<BlogContainer />} />
        {/* 新增:blogId作为路由参数占位 */}
        <Route path="/:blogId" element={<BlogPost />} />
      </Routes>
    </BrowserRouter>
  )
}

export default App;
  1. 简化列表页组件,删除多余的本地state和无效的onClick逻辑:
import { Link } from 'react-router-dom';
import Card from '../../shared/components/UIElements/Card';
import { useBlog } from '../../shared/hooks/blog-hook';

const BlogContainer = () => {
  const { blogs } = useBlog();
  const displayBlogs = blogs.map((blog) => (
    <Link
      to={`/${blog.key}`}
      key={blog.key}
    >
      <Card className="mapped">
        <h2>{blog.title}</h2>
        <h4>{blog.description}</h4>
      </Card>
    </Link>
  ));
  return <div className="blog-container">{displayBlogs}</div>;
};

export default BlogContainer;
  1. 修改详情页组件,通过useParams从URL取博客ID,再匹配对应博客内容渲染:
import { useParams } from 'react-router-dom';
import { useBlog } from '../../shared/hooks/blog-hook';

const BlogPost = () => {
  // 从URL中解析路由参数
  const { blogId } = useParams();
  const { blogs } = useBlog();
  // 匹配当前ID对应的博客数据
  const currentBlog = blogs.find(blog => blog.key === blogId);

  // 处理ID不存在的异常场景
  if (!currentBlog) {
    return <div className="error-tip">请求的博客不存在</div>
  }

  return (
    <article className="blog-detail">
      <h1>{currentBlog.title}</h1>
      {/* 这里根据你的博客数据结构渲染对应内容即可 */}
      <div className="blog-content">{currentBlog.content}</div>
    </article>
  );
};

export default BlogPost;
备选方案(全局状态传值,不推荐)

如果你坚持要通过点击事件存ID的方式实现,必须把blogID状态和更新方法放到useBlog自定义Hook中,让两个组件共享同一份状态,同时修改点击回调传入当前博客ID:

  1. 先修改useBlog自定义Hook,把blogID状态移到Hook内部:
// ../../shared/hooks/blog-hook.js
import { useState, useEffect } from 'react';

export const useBlog = () => {
  const [blogs, setBlogs] = useState([]);
  // 把blogID状态移到Hook中,所有调用useBlog的组件共享同一份状态
  const [blogID, setBlogID] = useState(null);

  // 保留你原有的博客列表拉取逻辑
  useEffect(() => {
    // 你的接口请求逻辑,比如fetchBlogs().then(res => setBlogs(res))
  }, []);

  return {
    blogs,
    blogID,
    setBlogID
  }
}
  1. 修改列表页的点击回调,传入当前点击项的blog.key:
import { Link } from 'react-router-dom';
import Card from '../../shared/components/UIElements/Card';
import { useBlog } from '../../shared/hooks/blog-hook';

const BlogContainer = () => {
  // 从共享Hook拿setBlogID方法,不要在组件内单独声明blogID状态
  const { blogs, setBlogID } = useBlog();

  const displayBlogs = blogs.map((blog) => (
    <Link
      // 点击时传入当前博客的key
      onClick={() => setBlogID(blog.key)}
      to={`/${blog.key}`}
      key={blog.key}
    >
      <Card className="mapped">
        <h2>{blog.title}</h2>
        <h4>{blog.description}</h4>
      </Card>
    </Link>
  ));
  return <div className="blog-container">{displayBlogs}</div>;
};

export default BlogContainer;

注意:这种方案有明显缺陷,用户如果直接输入详情页URL、或者刷新详情页,Hook里的状态会重置为初始值null,无法正常渲染内容,非特殊场景不建议使用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 21:39:27