如何将useRef用于htmlFor属性?

时间:2019-11-23 07:40:37

标签: reactjs react-hooks

我想自定义输入标签以上传文件。 这是我的代码。在这里,对于htmlFor属性,我给出了输入标签的ID,然后就可以了。但是我想使用useRef ref。我怎样才能做到这一点 ?如果我遵循以下方法,则多次渲染此组件会出现问题。对吗?

const App = () => {
  const inputRef = useRef(null);
  const [file, setFile] = useState(null);
  return (
    <>
      <input
        ref={inputRef}
        accept=".pdf"
        style={{ display: "none" }}
        id="raised-button-file"
        multiple
        type="file"
        onChange={e => {
          setFile(e.target.files[0]);
        }}
      />
      <label htmlFor="raised-button-file">
        <button component="span">
          <span>file</span>
        </button>
      </label>
    </>
  );
};

2 个答案:

答案 0 :(得分:0)

使用<label>标签的另一种方法是将元素包装为子元素,而无需为其指定id

<label>
  <input
    accept=".pdf"
    style={{ display: "none" }}
    multiple
    type="file"
    onChange={e => {
      setFile(e.target.files[0]);
    }}
  />
  <span>File</span>
</label>

如果您希望使用自己的引用打开文件输入对话框,则可以这样做。

const handleOpenFileInput = () => {
  inputRef.current.click();
};
<label onClick={handleOpenFileInput}>
  <button>file</button>
</label>
<input
  ref={inputRef}
  accept=".pdf"
  style={{ display: "none" }}
  multiple
  type="file"
  onChange={e => {
    setFile(e.target.files[0]);
  }}
/>

答案 1 :(得分:0)

如果您使用userRef,将无法解决您的问题。问题出在labelhtmlFor属性中。它不断获取其ID与htmlFor属性匹配的输入,并且由于多次渲染该组件,因此始终会得到第一个匹配项。

我只需将每个组件的id作为属性传递,以便每次标签与正确的输入匹配时。我将代码更改为如下所示:

const Form = ({id}) => {
  const onChangeInput = e => {
    const [file] = e.target.files
  }
  return (
    <form>
      <div>
        <input type="file" id={id} name="file" className="my-input" accept="application/pdf" style={{display:"none"}} onChange={onChangeInput} multiple/>
        <label htmlFor={id}>Upload</label>
      </div>
    </form>
  )
}

function App() {
  return (
    <div className="App">
      <Form id="form1"/>
      <Form id="form2"/>
      <Form id="form3"/>
    </div>
  );
}

为确保每个文档均已正确上传,我将className属性传递给输入,以便可以获取所有输入。运行这段代码,我找到了我上传的所有文件

Array.from(document.querySelectorAll('.my-input')).map(v => v.files[0].name)