【问题标题】:React dynamic form input useRef typeErrorReact 动态表单输入 useRef typeError
【发布时间】:2022-01-11 11:52:20
【问题描述】:

我有一个带有动态输入字段的 React 表单,用户可以添加和删除输入字段。我在提交表单时进行验证。如果 input 为空,则 input 使用 useRef 钩子聚焦。问题是,如果我有两个输入为空,所以我添加第二个输入并在之后删除它,我得到 typeError "Cannot read properties of null (reading 'focus')"。

App.js

import React, { useState, useRef } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  const [fields, setFields] = useState([""]);

  const fieldRef = useRef();

  const fieldsIsValid =
    fields.length >= 1 && fields.every((field) => field.trim() !== "");

  function handleChange(i, event) {
    const values = [...fields];
    values[i] = event.target.value;
    setFields(values);
  }

  function handleAdd() {
    const values = [...fields];
    values.push("");
    setFields(values);
  }

  function handleRemove(i) {
    const values = [...fields];
    values.splice(i, 1);
    setFields(values);
  }

  function submitHandler(event) {
    event.preventDefault();

    if (!fieldsIsValid) {
      if (fields.length >= 1) {
        fieldRef.current.focus();
        return;
      }
      return;
    }
    console.log(fields);
  }

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <form onSubmit={submitHandler}>
        <button type="button" onClick={() => handleAdd()}>
          Add Input
        </button>
        {!fieldsIsValid && <p className="error">Input is required</p>}
        {fields.map((field, idx) => {
          return (
            <div key={`${"input"}-${idx}`}>
              <input
                type="text"
                placeholder="Enter text"
                value={field || ""}
                ref={fieldRef}
                onChange={(e) => handleChange(idx, e)}
              />
              <button type="button" onClick={() => handleRemove(idx)}>
                X
              </button>
            </div>
          );
        })}
        <button className="margin-top" type="submit">
          Submit
        </button>
      </form>
    </div>
  );
}

export default App;

【问题讨论】:

标签: javascript reactjs forms react-hooks use-ref


【解决方案1】:

正如 Andreas 已经提到的,您需要为多个输入创建多个 ref。 React refs 到 DOM 节点总是存在一对一的映射/分配。如果您在多个位置使用相同的 ref,ref 将链接到您使用它的最后一个节点。为了帮助您理解这一点,请检查您在此处遇到的错误。它说,“无法读取 null 的属性”,即 fieldRef.current 的值为 null,因为在 DOM 树中删除后,最后一次映射的 DOM 节点 fieldRef(最后一个输入字段)不存在。

您可以尝试通过将 ref 放在表单标签而不是输入标签上来实现相同的功能,如下所示:

<form onSubmit={submitHandler} ref={fieldRef}>
function submitHandler(event) {
    event.preventDefault();

    for (let elem of fieldRef.current.elements) {
      if (elem.type === 'text' && elem.dataset.required && !elem.value) {
        elem.focus()
        return
      }
    }
  } 

<input
     type="text"
     data-required="true"    // <---- Add this here
     placeholder="Enter text"
     value={field || ""}
     onChange={(e) => handleChange(idx, e)}
 />

【讨论】:

  • 好吧,实际上我有一个包含许多静态输入和两个动态输入字段的大表单。我只发送一个 CodeSandBox,其中包含出现问题的表单的一部分。它会以具有许多静态输入和两个动态输入字段的大型形式工作吗?我的意思是如果将 ref 放在表单标签等中是一种好习惯。
  • 是的,它适用于包含数千个输入的表单。不用担心。你可以自己验证。 :)
  • 另外,如以下文档中所述,不要过度使用 refs。这实际上不是一个好习惯。只需在表单上有一个参考,这将解决您的问题。 reactjs.org/docs/refs-and-the-dom.html#dont-overuse-refs
  • 我试过了,但在我的情况下它不能按我的意愿工作。因为我过度使用了裁判。我对每个输入都有不同的参考。
  • 不要对每个输入使用 ref。只需在表单标签上添加一个 ref 即可解决您的问题。检查我上面提到的代码。
猜你喜欢
  • 1970-01-01
  • 2016-07-30
  • 1970-01-01
  • 2016-06-14
  • 1970-01-01
  • 1970-01-01
  • 2021-03-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多