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

React上传组件传参异常:点击与文件选择时参数不一致

问题:文件选择后UploadAvatar组件参数异常

在React项目中,为DataGrid内的指定用户传递属性至UploadAvatar组件实现文件上传功能时出现异常:

  • 点击第三个用户Michael Doe的头像,onClick中的console.log输出正确参数:mypic.png Michael Doe 3
  • 选择文件后,uploadAvatar函数中的console.log输出第一个用户的参数:app.png John Doe 1

相关代码

模拟数据

export default [
  {
    id: "1",
    name: "John Doe",
    avatar: "app.png"
  },
  {
    id: "2",
    name: "Anna Doe",
    avatar: "pic.png"
  },
  {
    id: "3",
    name: "Michael Doe",
    avatar: "mypic.png"
  }
];

Main组件中列配置

{
    field: "avatar",
    headerName: "Аватар",
    headerClassName: "home-header",
    editable: false,
    align: "center",
    headerAlign: "center",
    renderCell: (params) => (
      <UploadAvatar
        avatar={params.value}
        name={params.row.name}
        userId={params.row.id}
      />
    )
  },

UploadAvatar组件原代码

import React from "react";
import Avatar from "@mui/material/Avatar";

const UploadAvatar = ({
  avatar,
  name,
  userId
}: {
  avatar: string;
  name: string;
  userId: string;
}) => {
  const uploadAvatar = (e: any) => {
    const file = e.target.files[0];
    if (!file) return;
    console.log(avatar, name, userId);
  };
  return (
    <div>
      {avatar ? (
        <Avatar
          role="button"
          tabIndex={0}
          sx={{
            marginLeft: "-10px",
            marginRight: "10px",
            "&:hover": { cursor: "pointer" }
          }}
          alt="avatar"
          onClick={() => {
            console.log(avatar, name, userId);
            document.getElementById("avatar-input")!.click();
          }}
        ></Avatar>
      ) : (
        <Avatar
          role="button"
          tabIndex={0}
          sx={{
            marginLeft: "-10px",
            marginRight: "10px",
            "&:hover": { cursor: "pointer" }
          }}
          alt="avatar"
          src=""
          onClick={() => {
            document.getElementById("avatar-input")!.click();
          }}
        >
          {name
            ? name
                .split(/\s/)
                .reduce(
                  (response: any, word: any) => (response += word.slice(0, 1)),
                  ""
                )
            : ""}
        </Avatar>
      )}
      <input
        id="avatar-input"
        type="file"
        onChange={uploadAvatar}
        style={{ display: "none", position: "absolute" }}
        accept="image/*"
      />
    </div>
  );
};

export default UploadAvatar;

问题原因

所有UploadAvatar组件实例中的input都使用了相同的id="avatar-input"。当通过document.getElementById("avatar-input")获取元素时,DOM中只会返回第一个匹配该id的元素,因此无论点击哪个用户的头像,触发的都是第一个组件实例的input选择操作,对应的uploadAvatar函数自然也是第一个组件的,参数就变成了第一个用户的信息。

修复方案

方案一:生成唯一ID

为每个input生成唯一的id,结合传入的userId来区分:

import React from "react";
import Avatar from "@mui/material/Avatar";

const UploadAvatar = ({
  avatar,
  name,
  userId
}: {
  avatar: string;
  name: string;
  userId: string;
}) => {
  const inputId = `avatar-input-${userId}`;
  const uploadAvatar = (e: any) => {
    const file = e.target.files[0];
    if (!file) return;
    console.log(avatar, name, userId);
  };
  return (
    <div>
      {avatar ? (
        <Avatar
          role="button"
          tabIndex={0}
          sx={{
            marginLeft: "-10px",
            marginRight: "10px",
            "&:hover": { cursor: "pointer" }
          }}
          alt="avatar"
          onClick={() => {
            console.log(avatar, name, userId);
            document.getElementById(inputId)!.click();
          }}
        ></Avatar>
      ) : (
        <Avatar
          role="button"
          tabIndex={0}
          sx={{
            marginLeft: "-10px",
            marginRight: "10px",
            "&:hover": { cursor: "pointer" }
          }}
          alt="avatar"
          src=""
          onClick={() => {
            document.getElementById(inputId)!.click();
          }}
        >
          {name
            ? name
                .split(/\s/)
                .reduce(
                  (response: any, word: any) => (response += word.slice(0, 1)),
                  ""
                )
            : ""}
        </Avatar>
      )}
      <input
        id={inputId}
        type="file"
        onChange={uploadAvatar}
        style={{ display: "none", position: "absolute" }}
        accept="image/*"
      />
    </div>
  );
};

export default UploadAvatar;

方案二:使用React useRef(推荐)

避免直接操作DOM,用React的useRef来获取当前组件的input元素,更符合React的组件化思想:

import React, { useRef } from "react";
import Avatar from "@mui/material/Avatar";

const UploadAvatar = ({
  avatar,
  name,
  userId
}: {
  avatar: string;
  name: string;
  userId: string;
}) => {
  const inputRef = useRef<HTMLInputElement>(null);
  const uploadAvatar = (e: any) => {
    const file = e.target.files[0];
    if (!file) return;
    console.log(avatar, name, userId);
  };
  const triggerInputClick = () => {
    console.log(avatar, name, userId);
    inputRef.current?.click();
  };
  return (
    <div>
      {avatar ? (
        <Avatar
          role="button"
          tabIndex={0}
          sx={{
            marginLeft: "-10px",
            marginRight: "10px",
            "&:hover": { cursor: "pointer" }
          }}
          alt="avatar"
          onClick={triggerInputClick}
        ></Avatar>
      ) : (
        <Avatar
          role="button"
          tabIndex={0}
          sx={{
            marginLeft: "-10px",
            marginRight: "10px",
            "&:hover": { cursor: "pointer" }
          }}
          alt="avatar"
          src=""
          onClick={triggerInputClick}
        >
          {name
            ? name
                .split(/\s/)
                .reduce(
                  (response: any, word: any) => (response += word.slice(0, 1)),
                  ""
                )
            : ""}
        </Avatar>
      )}
      <input
        ref={inputRef}
        type="file"
        onChange={uploadAvatar}
        style={{ display: "none", position: "absolute" }}
        accept="image/*"
      />
    </div>
  );
};

export default UploadAvatar;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 01:01:51