在 React 中创建受控“<input type='file'>”元素的正确方法

use*_*003 3 forms reactjs react-hooks

大多数<input>元素使用valueprop 来设置值,因此它们可以由父元素进行外部控制。

然而,<input type='file'>从属性设置其值files,我正在努力使其正常工作。files不能直接设置为 prop,但可以通过 ref 直接在 DOM 上设置,所以我使用useEffect()以下方法来完成此操作:

import React, { useEffect, useRef } from "react";

const FileInput = (props) => {
  const { value } = props;
  const inputRef = useRef();
  
  useEffect(() => {
    if (value === "") {
      inputRef.current.value = "";
    } else {
      inputRef.current.files = value;
    }
  }, [value]);
  
  return <input type="file" ref={inputRef} />;
};

export default FileInput;
Run Code Online (Sandbox Code Playgroud)

我想onChange()在用户选择文件时包含一个处理程序,但该<FileList>对象与 DOM 绑定,并且在尝试使用它来设置时出现错误value

DOMException: An attempt was made to use an object that is not, or is no longer, usable
Run Code Online (Sandbox Code Playgroud)

我一直在以“正确”的方式编写受控表单输入。有没有办法正确设置files属性和value属性?

谢谢!

sli*_*wp2 6

首先,我们从中知道How to set a value to a file input in HTML? 问题是我们无法以编程方式设置元素value的属性<input type='file'/>

其次,我们从这个/sf/answers/4772751091/答案中知道我们可以files通过DataTransfer设置属性。

所以该FileInput组件可以是:

import { useEffect, useRef } from 'react';
import * as React from 'react';

export type FileInputProps = {
  fileList: File[];
  onChange(fileList: FileList): void;
};
const FileInput = ({ fileList = [], onChange }: FileInputProps) => {
  const inputRef = useRef<HTMLInputElement>(null);

  useEffect(() => {
    if (inputRef.current) {
      const dataTransfer = new DataTransfer();
      fileList.forEach((file) => dataTransfer.items.add(file));
      inputRef.current.files = dataTransfer.files;
    }
  }, [fileList]);

  return (
    <input
      type="file"
      ref={inputRef}
      data-testid="uploader"
      onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
        onChange(e.target.files);
      }}
    />
  );
};

export default FileInput;
Run Code Online (Sandbox Code Playgroud)

有关现场演示,请参阅stackblitz