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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 15:07:06