【问题标题】:React parent component needs child function to return dataReact父组件需要子函数返回数据
【发布时间】:2021-12-05 19:38:55
【问题描述】:

我想我需要一个回调函数,但由于父组件调用子函数,我不理解正确的语法。

这是剥离的父组件,后面是函数 FilesUpload。 我需要返回子组件的 File.Name 和父组件中的 setState({fileName})。

希望对于知道如何做到这一点的人来说是显而易见的。 提前感谢您的解决方案。 抢 @davidsz - 有什么想法吗? ...

//Stripped down ParentComponent.jsx
import React, { Component } from 'react'
import FilesUpload from "../Services/FilesUpload";

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

    changefileNameHandler= (event) => {
        this.setState({fileName: event.target.value});
    }

    componentDidMount(){
    }
   
    render() {
        return (
            <div>
                <td>this.state.fileName </td>
                <FilesUpload onUpdate={this.changefileNameHandler}/>
            </div>
        )
    }
}
export default ParentComponent


//functional service 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';


const UploadFiles = () => {
  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")
        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">
        {/* <div className="card-header">List of Files</div> */}
        <ul className="list-group list-group-flush">
          {!fileInfos &&
            fileInfos.map((file, index) => (
              <li className="list-group-item" key={index}>
                {/* <a href={file.url}>{file.name}</a> */}
              </li>
            ))}
        </ul>
      </div>
      <ToastContainer position="top-center" autoClose={1000}/>
    </div>
  );
};

export default UploadFiles;

...

【问题讨论】:

    标签: reactjs function react-hooks callback components


    【解决方案1】:

    我不太确定我是否完全理解你的问题,但你想将changefileNameHandler 函数作为道具传递给你的FilesUpload 函数组件吗?

    在这种情况下,您可以只添加道具作为参数:

    const UploadFiles = (props) => { ...
    

    在需要的地方调用它:

    props.onUpdate(event)
    

    【讨论】:

    • 戴夫,谢谢您的回复。我需要使用 toast.info(file.name + "Uploaded") 行的 FilesUpload 功能组件中的 file.name 值更新 ParentComponent 中的变量“fileName”。不幸的是,我需要确切的代码和位置。当我尝试解释预期良好的缩短伪代码时,我不断收到错误消息或没有结果。能否提供更详细的答案。我欠你一杯啤酒。 @davidsz
    • 这是我得到的: 第 1 行 const UploadFiles = (props) => { 第 34 行 props.onUpdate(event) toast.info(file.name + " Uploaded") 编译器错误:意外使用事件如此接近! @davidsz
    • 使用 props.onUpdate(file.name) 似乎处理并调用了 ParentComponent 中的 changefileNameHandler,但 fileName 永远不会在屏幕上更新。令我费解。 @davidsz
    • 如果将 file.name 作为参数添加到 onUpdate 函数,而不是事件,则需要以这种方式定义函数。所以:changefileNameHandler= (fileName) => {this.setState({fileName: fileName});}
    猜你喜欢
    • 2022-01-15
    • 1970-01-01
    • 2014-01-16
    • 2017-09-22
    • 2021-11-25
    • 2020-07-13
    • 2018-11-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多