React Hooks - 输入 1 个字符时,输入失去焦点

Dra*_*gar 16 reactjs react-hooks

我正在使用 React Hooks - 重写表单以使用钩子概念。一切都按预期工作,除了一旦我在输入中输入任何 1 个字符,输入就会失去焦点。

我猜有一个问题,组件的外部不知道组件内部的变化,但是我该如何解决这个问题呢?

这是 useForm 钩子:

import React, { useState } from "react";

export default function useForm(defaultState, label) {
  const [state, setState] = useState(defaultState);

  const FormComponent = () => (
    <form>
      <label htmlFor={label}>
        {label}
        <input
          type="text"
          id={label}
          value={state}
          placeholder={label}
          onChange={e => setState(e.target.value)}
        />
      </label>
    </form>
  );

  return [state, FormComponent, setState];
}
Run Code Online (Sandbox Code Playgroud)

这是使用 Hook 的组件:

function App() {
  const [formValue, Form, setFormValue] = useForm("San Francisco, CA", "Location");

  return (
    <Fragment>
      <h1>{formValue}</h1>
      <Form />
    </Fragment>
  );
}
Run Code Online (Sandbox Code Playgroud)

Kas*_*kas 20

虽然 Kais 的回答可以解决症状,但它不会解决问题的原因。如果有多个输入,它也会失败 - 那么哪个应该自动聚焦于重新渲染?

当您FormComponent在另一个函数的作用域内定义一个组件 ( )时会发生问题,该函数在您的App组件的每个渲染中都被调用。这给你一个全新的FormComponent你每次App组件重新呈现和电话useState。那么,那个新组件就没有焦点了。

就我个人而言,我会再次从钩子中返回组件。我会改为定义一个FormComponent组件,并且只从 useForm 状态返回状态。

但是,最接近原始代码的工作示例可能是:

// useForm.js
import React, { useState } from "react";

// Define the FormComponent outside of your useForm hook
const FormComponent = ({ setState, state, label }) => (
  <form>
    <label htmlFor={label}>
      {label}
      <input
        type="text"
        id={label}
        value={state}
        placeholder={label}
        onChange={e => setState(e.target.value)}
      />
    </label>
  </form>
);

export default function useForm(defaultState, label) {
  const [state, setState] = useState(defaultState);

  return [
    state,
    <FormComponent state={state} setState={setState} label={label} />,
    setState
  ];
}
Run Code Online (Sandbox Code Playgroud)
// App.js
import useForm from "./useForm";

export default function App() {
  const [formValue, Form] = useForm("San Francisco, CA", "Location");

  return (
    <>
      <h1>{formValue}</h1>
      {Form}
    </>
  );
}
Run Code Online (Sandbox Code Playgroud)

这是一个沙箱

  • 这应该是答案。 (3认同)
  • @AlfonsoTienda它之所以有效,是因为我将“FormComponent”移到了“useForm”函数之外,因此它始终指向同一个对象(与每次调用“useForm”函数时创建的新对象相反)。因此,React 不再确定“FormComponent”的整个 DOM 表示需要完全重绘(对象相同,除了输入值之外没有任何变化)。然后,“isFocused”或类似标志**在重绘过程​​中不再丢失**。请记住,每次用户输入内容时,React 都会调用“useForm”并更新状态。至少我是这么理解的。 (3认同)
  • 这真的有效!但我不明白为什么。请您解释一下为什么您的解决方案有效? (2认同)

Kai*_*ais 12

当您在输入框中输入任何文本时。父组件也在重新渲染。所以你需要手动关注输入。为此,autoFocus在输入标签中使用

<input
  type="text"
  id={label}
  value={state}
  placeholder={label}
  onChange={e => setState(e.target.value)}
  autoFocus
/>
Run Code Online (Sandbox Code Playgroud)

  • 这不适用于存在焦点问题的表单中的多个输入。 (2认同)

cod*_*ire 12

上面的答案对我不起作用。对我有用的解决方案要简单得多,因此也不太明显。

问题 本质上,我随输入更改的值也用于key输入列表中的每个值。

因此,当我更新该值时,该值key会发生变化,React 会检测到它相对于最后一个键有所不同,并在其位置创建一个新输入。作为一个新的输入,它不会关注自身。

但是,通过使用autoFocus它会自动关注新创建的输入。但问题并没有得到解决,因为很明显,输入不断经历不聚焦和聚焦的循环。

这是一篇演示该问题的文章

修复方法

将 更新key为不可更改的值,以便 React 对列表项有稳定的引用。就我而言,我只是将其更新到索引。这并不理想(React 文档建议使用稳定的 ID),但在我的情况下没关系,因为项目的顺序不会改变。

  • 这个解决方案帮助我在几个小时后找到了我的问题并得到了支持。我使用“nanoid()” id 生成器作为“key”。改成唯一id后问题就解决了。 (2认同)