React中实现点击子组件按钮后重置其他子组件状态
问题:点击卡片按钮后仅当前按钮显示“Copied!”,其他按钮恢复“Copy”
父组件代码:
const Users = [ { id: 1, name: "abc", age: 12, }, { id: 2, name: "def", age: 22, }, { id: 3, name: "abf", age: 32, }, ]; {Users.map((h, index) => { return ( <React.Fragment key={index}> <User data={h} /> <br></br> </React.Fragment> ); })}
子组件User.js代码:
import { useState } from "react"; import "./style.css"; function User(user) { const [copyTxt, setCopyTxt] = useState("Copy"); const [copyClass, setCopyClass] = useState("button_copy"); const handleCopy = () => { setCopyTxt("Copied!"); setCopyClass("button_copied"); }; return ( <div className="user_div"> <div className="p-2 flex-fill button_div"> <button type="submit" onClick={handleCopy} className={copyClass}> {copyTxt} </button> </div> </div> ); } export default User;
当前问题:依次点击3个按钮后,所有按钮文本均变为Copied!,预期仅最后点击的按钮显示Copied!,其他恢复为Copy。
解决方案
核心思路是将状态提升到父组件,让所有子组件共享同一个状态源,以此控制只有当前点击的按钮显示“Copied!”状态。
1. 修改父组件
添加状态记录最后点击的用户ID,并将该状态和更新方法传递给子组件:
import { useState } from "react"; import User from "./User"; function ParentComponent() { const Users = [ { id: 1, name: "abc", age: 12 }, { id: 2, name: "def", age: 22 }, { id: 3, name: "abf", age: 32 }, ]; // 记录最后点击的用户ID,初始为null const [copiedUserId, setCopiedUserId] = useState(null); return ( <div> {Users.map((user) => ( <React.Fragment key={user.id}> {/* 传递用户数据、当前复制状态ID、状态更新方法 */} <User data={user} copiedUserId={copiedUserId} setCopiedUserId={setCopiedUserId} /> <br /> </React.Fragment> ))} </div> ); } export default ParentComponent;
2. 修改子组件User.js
移除子组件自身的状态,直接根据父组件传递的copiedUserId判断当前按钮的显示状态:
import "./style.css"; function User({ data, copiedUserId, setCopiedUserId }) { // 根据当前用户ID是否等于父组件记录的ID,决定显示文本和类名 const isCopied = copiedUserId === data.id; const copyTxt = isCopied ? "Copied!" : "Copy"; const copyClass = isCopied ? "button_copied" : "button_copy"; const handleCopy = () => { // 点击时更新父组件的状态,记录当前用户ID setCopiedUserId(data.id); }; return ( <div className="user_div"> <div className="p-2 flex-fill button_div"> <button type="button" onClick={handleCopy} className={copyClass} > {copyTxt} </button> </div> </div> ); } export default User;
补充说明
- 父组件维护唯一的
copiedUserId状态,所有子组件都依赖这个状态判断自己的显示样式,点击任意按钮时,父组件更新状态,所有子组件同步渲染,仅匹配ID的按钮显示“Copied!”。 - 建议用用户的
id作为列表项的key,比index更稳定,避免列表更新时出现不必要的渲染问题。
内容的提问来源于stack exchange,提问作者Mr_Sharma
相关产品推荐
相关产品推荐

