【问题标题】:Reactjs: programmatically focusing on a programmatically generated inputReactjs:以编程方式关注以编程方式生成的输入
【发布时间】:2019-10-10 16:43:51
【问题描述】:

我有一个应用程序可以呈现一个可编辑的表格,每行有几个输入元素。由于该表填充了用户条目,因此它可以是可变长度的。表中的某些用户条目将无效。当条目无效时,我想显示一条警告,上面写着“您输入了无效数据”,然后将用户重点放在输入无效条目上。

通读文档,一个 ref 似乎是最好的做事方式。但是,我发现的所有示例,无论是来自 React 团队还是 Stack Overflow,都显示单个输入绑定到单个 ref。某些操作(通常是单击按钮)被硬编码以引用特定的 ref,并且一切正常。

我想确定在出现错误时访问相关输入的最佳方法。做到这一点的“最佳”方法似乎是创建一个 refs 数组,然后为每个输入分配一个 ref——但文档也强调要谨慎使用 refs,这感觉像是对 refs 的严重滥用。

我更喜欢创建单个 ref,然后将其重新分配给最近更新的输入。每次用户失去焦点时,它都会检查是否强制将焦点放在包含错误数据的输入上。这感觉它有可能成为一种反模式,尤其是因为我找不到任何其他人实施它的证据。

我很想知道解决这个问题的最佳方法,因为我担心我的两个想法都不是好的前进道路。

【问题讨论】:

    标签: reactjs focus


    【解决方案1】:

    您不能依赖输入的单个引用,而是依赖容器引用。您始终拥有一个容器 ref,并且每当用户模糊输入时,您必须使用 .querySelectorAll('input') 从容器中获取所有输入,找到无效的并聚焦它。

    const {
      useState,
      useCallback,
      useMemo,
      useRef,
      useEffect
    } = React;
    
    const defaultUsers = [
      { id: 1, name: "User #1", email: "user1@gmail.com" },
      { id: 2, name: "User #2", email: "user2@gmail.com" },
      { id: 3, name: "User #3", email: "user3@gmail.com" },
      { id: 4, name: "User #4", email: "user4@gmail.com" },
      { id: 5, name: "", email: "user5@gmail.com" },
      { id: 6, name: "User #6", email: "user6@gmail.com" },
      { id: 7, name: "User #7", email: "user7@gmail.com" },
      { id: 8, name: "User #8", email: "" },
      { id: 9, name: "User #9", email: "user9@gmail.com" },
      { id: 10, name: "User #10", email: "user10@gmail.com" }
    ];
    
    const App = () => {
      const tbodyRef = useRef();
    
      const focusNextInvalidInput = useCallback(() => {
        if (tbodyRef.current) {
          const inputs = tbodyRef.current.querySelectorAll("td > input");
          for (const input of inputs) {
            if (input.value.length === 0) {
              input.focus();
              return;
            }
          }
        }
      }, [tbodyRef]);
    
      useEffect(() => {
        focusNextInvalidInput();
      }, [focusNextInvalidInput]);
    
      const [users, setUsers] = useState(defaultUsers);
    
      const updateUserField = useCallback(
        (id, field, value) =>
          setUsers(
            users.map(user => (user.id === id ? { ...user, [field]: value } : user))
          ),
        [users]
      );
    
      const changeUserName = useCallback(
        (id, name) => updateUserField(id, "name", name),
        [updateUserField]
      );
      const changeUserEmail = useCallback(
        (id, email) => updateUserField(id, "email", email),
        [updateUserField]
      );
    
      const usersRows = useMemo(() => {
        return users.map(({ id, name, email }) => (
          <tr key={id}>
            <td>{id}</td>
            <td>
              <input
                type="text"
                onChange={e => changeUserName(id, e.target.value)}
                value={name}
                onBlur={focusNextInvalidInput}
              />
            </td>
            <td>
              <input
                type="email"
                onChange={e => changeUserEmail(id, e.target.value)}
                value={email}
                onBlur={focusNextInvalidInput}
              />
            </td>
          </tr>
        ));
      }, [users, changeUserEmail, changeUserName, focusNextInvalidInput]);
    
      return (
        <table>
          <thead>
            <tr>
              <th>ID</th>
              <th>Name</th>
              <th>Email</th>
            </tr>
          </thead>
          <tbody ref={tbodyRef}>{usersRows}</tbody>
        </table>
      );
    };
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);
    <script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
    <div id="root"></div>

    CodeSandbox example.

    【讨论】:

    • 非常感谢您的意见。所以目标本质上是为整个表提供一个参考,然后在每个模糊上搜索每个子项以找到无效数据。当我们发现无效数据时,我们可以相应地更新。我们正在使用 useCallback 和 useMemo ,因为除了其中一个字段之外,我们不需要被所有字段所困扰。非常感谢!它仍然有点模糊,但这就是一切,直到你尝试它!感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 2011-04-27
    • 1970-01-01
    • 2010-09-06
    • 2018-06-23
    • 2018-08-14
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    相关资源
    最近更新 更多