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

React中按Item Key打开模态框及实现博客分页的问题求助

解决博客模态框显示重复数据及分页实现方案

我看到你现在遇到两个问题——打开模态框时总是显示相同的博客内容,以及需要实现每页10条的分页功能。咱们一步步来解决这些问题:

一、修复模态框显示重复数据的问题

问题根源

你现在的cardDialog方法会遍历所有博客,渲染每个博客对应的Dialog组件,而且所有Dialog的open状态都绑定到同一个this.state.openDialog。当你打开模态框时,所有Dialog都会被触发显示,但视觉上最后一个会覆盖前面的,所以看起来都是同一条数据。

解决方案

我们不需要渲染所有Dialog,只需要渲染当前选中的那一条博客的Dialog就可以了:

  1. 修改State结构:在state里添加selectedBlog来存储当前选中的博客对象
constructor(props) {
  super(props);
  this.state = { 
    modal: false,
    openDialog: false,
    selectedBlog: null // 新增:存储选中的博客
  };
  this.handleOpenDialog = this.handleOpenDialog.bind(this);
  this.handleCloseDialog = this.handleCloseDialog.bind(this);
}
  1. 更新打开模态框的方法:点击"Read"按钮时,找到对应的博客对象并存入state
handleOpenDialog(id) {
  // 从博客数组中匹配选中的博客
  const selectedBlog = this.props.resume.blogs.find(blog => blog._id === id);
  this.setState({ 
    openDialog: true,
    selectedBlog: selectedBlog
  });
}
  1. 重构模态框渲染逻辑:只渲染当前选中的博客的Dialog
    把原来的cardDialog方法替换成下面的逻辑:
renderDialog() {
  const { selectedBlog, openDialog } = this.state;
  if (!selectedBlog || !openDialog) return null; // 无选中博客或模态框关闭时不渲染

  return (
    <Dialog open={openDialog} className="open-dialog">
      <FABButton onClick={this.handleCloseDialog} className="close-button" mini ripple>
        <Icon name="close" />
      </FABButton>
      <DialogTitle>{selectedBlog.blog_short_desc}</DialogTitle>
      <img className="blogs-contents-image" src={selectedBlog.blog_image_link} alt="blogs"/>
      <h4>{selectedBlog.blog_name}</h4>
      <DialogContent className="dialog-contents">{selectedBlog.blog_desc}</DialogContent>
    </Dialog>
  );
}
  1. 在render中调用这个方法:替换原来的{this.cardDialog(blogs, user)}
// ... 其他render内容
{this.renderDialog()}
// ...

这样修改后,每次点击"Read"按钮只会渲染对应选中的博客的Dialog,不会再出现重复数据的问题。

二、实现每页10条的分页功能

步骤1:添加分页相关的State

constructor(props) {
  super(props);
  this.state = { 
    modal: false,
    openDialog: false,
    selectedBlog: null,
    currentPage: 1, // 当前页码
    postsPerPage: 10 // 每页显示条数
  };
  this.handleOpenDialog = this.handleOpenDialog.bind(this);
  this.handleCloseDialog = this.handleCloseDialog.bind(this);
}

步骤2:计算当前页要显示的博客列表

在render方法里,根据当前页码和每页条数截取对应的数据:

render() {
  const { blogs, loading} = this.props.resume;
  const { currentPage, postsPerPage } = this.state;

  // 计算当前页的博客范围
  const indexOfLastPost = currentPage * postsPerPage;
  const indexOfFirstPost = indexOfLastPost - postsPerPage;
  const currentBlogs = blogs.slice(indexOfFirstPost, indexOfLastPost);

  // 计算总页数
  const totalPages = Math.ceil(blogs.length / postsPerPage);

  // ... 其他代码不变,把原来的blogs.map替换成currentBlogs.map
  <Grid id="todo">
    {currentBlogs.map(({ _id, blog_name, blog_by, date }) => (
      // ... 原来的Card内容保持不变
    ))}
  </Grid>
  // ...
}

步骤3:添加分页控制按钮

先定义一个分页组件,然后在render中调用:

// 分页控制组件(可以单独提取成文件)
const Pagination = ({ currentPage, totalPages, paginate }) => {
  const pageNumbers = [];
  for (let i = 1; i <= totalPages; i++) {
    pageNumbers.push(i);
  }

  return (
    <nav style={{ marginTop: '2rem', textAlign: 'center' }}>
      <ul style={{ listStyle: 'none', padding: 0, display: 'inline-flex', gap: '0.5rem' }}>
        {/* 上一页按钮 */}
        <li>
          <button 
            onClick={() => paginate(currentPage - 1)} 
            disabled={currentPage === 1}
            style={{ padding: '0.5rem 1rem', cursor: 'pointer', border: '1px solid #ddd', borderRadius: '4px' }}
          >
            上一页
          </button>
        </li>
        {/* 页码按钮 */}
        {pageNumbers.map(number => (
          <li key={number}>
            <button 
              onClick={() => paginate(number)}
              style={{ 
                padding: '0.5rem 1rem', 
                cursor: 'pointer', 
                border: '1px solid #ddd', 
                borderRadius: '4px',
                backgroundColor: currentPage === number ? '#007bff' : 'white',
                color: currentPage === number ? 'white' : 'black'
              }}
            >
              {number}
            </button>
          </li>
        ))}
        {/* 下一页按钮 */}
        <li>
          <button 
            onClick={() => paginate(currentPage + 1)} 
            disabled={currentPage === totalPages}
            style={{ padding: '0.5rem 1rem', cursor: 'pointer', border: '1px solid #ddd', borderRadius: '4px' }}
          >
            下一页
          </button>
        </li>
      </ul>
    </nav>
  );
};

然后在render里引入这个组件:

// ... 其他render内容
<Pagination 
  currentPage={this.state.currentPage}
  totalPages={totalPages}
  paginate={(pageNumber) => this.setState({ currentPage: pageNumber })}
/>
// ...

这样就完成了分页功能,每页显示10条博客,点击页码可以切换页面。

小优化建议

  • 当删除博客后,如果当前页数据为空,自动切换到上一页,避免出现空页面
  • 可以把Pagination组件单独提取成独立文件,让代码结构更清晰

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 11:03:10