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
相关产品推荐
相关产品推荐

