React使用map渲染列表时如何单独修改单个元素的状态值
问题原因
你当前所有的复制按钮共用了同一个全局的buttonText状态,只要触发一次状态修改,所有绑定该状态的按钮文本都会同步更新,因此会出现点击任意按钮所有按钮都变"Copied"的问题。
实现方案
我们可以给每个短链接项单独加复制状态标记,实现单个按钮状态独立控制,步骤如下:
- 移除全局的
buttonText状态,改为在短链接列表的每个条目里新增copied字段,默认值为false,单独记录每个按钮的复制状态 - 渲染按钮时根据当前条目的
copied字段判断显示文本 - 点击复制按钮时,仅修改当前点击条目对应的
copied状态,还可加定时重置逻辑提升使用体验
修正后代码
import {useState} from 'react' import axios from 'axios' import { v4 as uuidv4 } from 'uuid'; function Main() { const [name, setName] = useState('') // 初始列表如果有默认值,也要给每个项加copied: false字段 const [list, setList] = useState([]); const handleSubmit = (e) => { e.preventDefault(); } const handleAdd = async () => { const res = await axios.get(`https://api.shrtco.de/v2/shorten?url=${name}`) const {data: {result: {full_short_link: shortLink}}} = res // 新增项添加copied字段,默认为false const newList = list.concat({name:shortLink, id: uuidv4(), copied: false}); setList(newList); setName(''); } // 复制按钮点击处理 const handleCopy = (item) => { navigator.clipboard.writeText(item.name); // 仅更新当前点击项的copied状态 setList(prevList => prevList.map(link => { if(link.id === item.id) { return {...link, copied: true} } return link })) // 可选:2秒后自动变回Copy文本 setTimeout(() => { setList(prevList => prevList.map(link => { if(link.id === item.id) { return {...link, copied: false} } return link })) }, 2000) } return ( <div> <form onSubmit={handleSubmit}> <input type="text" value= {name} onChange={(e) => setName(e.target.value)} placeholder='Shorten a link here' /> <button onClick = {handleAdd}>Shorten it!</button> </form> <ul> {list.map((item) => ( <li key={item.id}> {item.name} <button onClick={() => handleCopy(item)}> {/* 根据当前项的copied状态显示对应文本 */} {item.copied ? 'Copied' : 'Copy'} </button> </li> ))} </ul> </div> ) } export default Main
内容的提问来源于stack exchange,提问作者KiranM
相关产品推荐
相关产品推荐

