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

React列表点击事件仅作用于单个项问题:如何单独标记诗歌为已读

解决React中单个诗歌标记已读时所有项受影响的问题

我是React新手,尝试将db.json文件中的某一首诗歌标记为已读,但点击按钮时所有诗歌项都会受影响,请问如何实现每次仅选中单个项进行标记?

原代码:

import React , {useState, useEffect} from "react";

function Poem() {
  
  const [poemShow, setPoemShow] = useState([])
  
  const PoemData = "http://localhost:8004/poems"
  // to load the Poem
  useEffect(() => {
    fetch(PoemData)
    .then((res) => res.json())
    .then((data) => {setPoemShow(data)})
    // .then((data) => console.log(data))
  }, []);
  
  const [unread, setUnread] = useState(false)
  function markRead(event) {
    console.log({unread, setUnread})
    setUnread(!unread)
    // console.log( `${item.id} marked`)
  }

  return (
    <div>
        {poemShow.map((item) => (
          <div key={item.id}>
            <h3>{item.title}</h3>
            <p>{item.content}</p>
            <strong>{item.author}</strong><br/>
            {/* <button onClick={markRead}>{unread ? "Mark as unread" : "Mark as read" }</button> */}
            <button onClick={(event) => markRead(event.target.id)}>{unread ? "Mark as unread" : "Mark as read" }</button>

            <hr/>
          </div>
        ))}
    </div>
  );
}

export default Poem;

问题原因

你当前使用了一个全局的unread布尔值状态,所有诗歌组件共用这个状态。当你点击任意按钮切换unread的值时,所有诗歌的按钮文字都会跟着变化,因为它们都依赖同一个全局状态判断显示内容。

解决方案

需要为每首诗歌单独记录已读状态,推荐使用存储已读诗歌ID的集合(Set)或数组来跟踪哪些诗歌被标记为已读,这样就能实现单个项的独立状态管理。

修改后的代码

import React, { useState, useEffect } from "react";

function Poem() {
  const [poemShow, setPoemShow] = useState([]);
  const PoemData = "http://localhost:8004/poems";

  // 加载诗歌数据
  useEffect(() => {
    fetch(PoemData)
      .then((res) => res.json())
      .then((data) => setPoemShow(data));
  }, []);

  // 用Set存储已读诗歌的ID,初始为空
  const [readPoemIds, setReadPoemIds] = useState(new Set());

  // 根据诗歌ID切换已读状态
  function markRead(poemId) {
    setReadPoemIds((prev) => {
      const newReadSet = new Set(prev);
      // 如果已存在则移除,不存在则添加
      if (newReadSet.has(poemId)) {
        newReadSet.delete(poemId);
      } else {
        newReadSet.add(poemId);
      }
      return newReadSet;
    });
  }

  return (
    <div>
      {poemShow.map((item) => (
        <div key={item.id}>
          <h3>{item.title}</h3>
          <p>{item.content}</p>
          <strong>{item.author}</strong><br />
          {/* 根据当前诗歌ID是否在已读集合中显示对应文字 */}
          <button onClick={() => markRead(item.id)}>
            {readPoemIds.has(item.id) ? "标记为未读" : "标记为已读"}
          </button>
          <hr />
        </div>
      ))}
    </div>
  );
}

export default Poem;

关键修改点说明

  • 把全局布尔状态unread替换为readPoemIds(Set类型),用来存储所有已读诗歌的ID
  • markRead函数现在接收诗歌ID作为参数,通过操作Set来切换对应ID的已读状态
  • 按钮的显示文字根据当前诗歌ID是否存在于readPoemIds中来判断,实现单个项的独立状态控制

如果偏好使用数组而非Set,也可以这样修改状态和函数:

// 用数组存储已读ID
const [readIds, setReadIds] = useState([]);

function markRead(poemId) {
  setReadIds((prev) => {
    if (prev.includes(poemId)) {
      // 已读则移除
      return prev.filter(id => id !== poemId);
    } else {
      // 未读则添加
      return [...prev, poemId];
    }
  });
}

// 按钮文字判断
{readIds.includes(item.id) ? "标记为未读" : "标记为已读"}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 20:16:11