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

React父组件调用文件上传子组件时如何获取返回文件名并更新state

解决方案

你需要做3处核心修改即可实现需求:

1. 修正父组件逻辑

首先修改父组件的回调函数,适配直接接收文件名参数,同时修正模板渲染的语法错误:

// ParentComponent.jsx
import React, { Component } from 'react'
// 注意导入名称要和子组件导出的名称对应,你之前子组件导出的是UploadFiles,这里保持一致即可
import UploadFiles from "../Services/FilesUpload";

class ParentComponent extends Component {
    constructor(props) {
        super(props)
        this.state = {
            fileName: null
        }
    }

    // 修改回调:直接接收文件名参数,不需要读取event.target.value
    changefileNameHandler = (fileName) => {
        this.setState({fileName: fileName});
    }
   
    render() {
        return (
            <div>
                {/* 修正渲染语法,要加花括号才能读取state值 */}
                <td>{this.state.fileName}</td>
                <UploadFiles onUpdate={this.changefileNameHandler}/>
            </div>
        )
    }
}
export default ParentComponent

2. 修正子组件逻辑

首先接收父组件传入的onUpdate回调,在文件上传成功的位置触发回调传入文件名即可:

// FilesUpload.js
import React, { useState, useEffect, useRef } from "react";
import UploadService from "../Services/FileUploadService";
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

// 接收父组件传入的onUpdate参数
const UploadFiles = ({ onUpdate }) => {
  const [selectedFiles, setSelectedFiles] = useState(undefined);
  const [progressInfos, setProgressInfos] = useState({ val: [] });
  const [message, setMessage] = useState([]);
  const [fileInfos, setFileInfos] = useState([]);
  const progressInfosRef = useRef(null)

  useEffect(() => {
    UploadService.getFiles().then((response) => {
      setFileInfos(response.data);
    });
  }, []);

  const selectFiles = (event) => {
    setSelectedFiles(event.target.files);
    setProgressInfos({ val: [] });
  };

  const upload = (idx, file) => {
    let _progressInfos = [...progressInfosRef.current.val];
    return UploadService.upload(file, (event) => {
      _progressInfos[idx].percentage = Math.round(
        (100 * event.loaded) / event.total
      );
      setProgressInfos({ val: _progressInfos });
    })
      .then(() => {
        toast.info(file.name + " Uploaded")
        // 上传成功后触发父组件回调,传入当前文件的名称
        onUpdate?.(file.name)
        setMessage((prevMessage) => ([
          ...prevMessage,
          "Uploaded the file successfully: " + file.name,
        ]));
      })
      .catch(() => {
        _progressInfos[idx].percentage = 0;
        setProgressInfos({ val: _progressInfos });

        setMessage((prevMessage) => ([
          ...prevMessage,
          "Could not upload the file: " + file.name,
        ]));
      });
  };

  const uploadFiles = () => {
    const files = Array.from(selectedFiles);

    let _progressInfos = files.map(file => ({ percentage: 0, fileName: file.name }));

    progressInfosRef.current = {
      val: _progressInfos,
    }

    const uploadPromises = files.map((file, i) => upload(i, file));

    Promise.all(uploadPromises)
      .then(() => UploadService.getFiles())
      .then((files) => {
        setFileInfos(files.data);
      });

    setMessage([]);
  };

  return (
    <div>
      {progressInfos && progressInfos.val.length > 0 &&
        progressInfos.val.map((progressInfo, index) => (
          <div className="mb-2" key={index}>
            <span>{progressInfo.fileName}</span>
            <div className="progress">
              <div
                className="progress-bar progress-bar-info"
                role="progressbar"
                aria-valuenow={progressInfo.percentage}
                aria-valuemin="0"
                aria-valuemax="100"
                style={{ width: progressInfo.percentage + "%" }}
              >
                {progressInfo.percentage}%
              </div>
            </div>
          </div>
        ))}

      <div className="row my-3">
        <div className="col-8">
          <label className="btn btn-default p-0">
            <input type="file" multiple onChange={selectFiles} />
          </label>
        </div>

        <div className="col-4">
          <button
            className="btn btn-success btn-sm"
            disabled={!selectedFiles}
            onClick={uploadFiles}
          >
            Upload
          </button>
        </div>
      </div>
      {message.length > 0 && (
        <div className="alert alert-secondary" role="alert">
          <ul>
            {message.map((item, i) => {
              return <li key={i}>{item}</li>;
            })}
          </ul>
        </div>
      )}

      <div className="card">
        <ul className="list-group list-group-flush">
          {/* 修正判断逻辑,原来的!fileInfos会导致有数据时不渲染 */}
          {fileInfos &&
            fileInfos.map((file, index) => (
              <li className="list-group-item" key={index}>
              </li>
            ))}
        </ul>
      </div>
      <ToastContainer position="top-center" autoClose={1000}/>
    </div>
  );
};

export default UploadFiles;

多文件上传适配说明

如果你的业务是多文件上传,需要存储所有上传文件的名称,可以把父组件的state改成数组类型,子组件所有文件上传完成后一次性传入文件名数组即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 21:27:03