我正在玩 React Hooks - 重写表单以使用钩子概念。一切都按预期工作,除了一旦我在输入中键入任何 1 个字符,输入就会失去焦点。
我想有一个问题,即组件的外部不知道组件中的内部更改,但是我该如何解决此问题?
这是使用表单钩子:
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];
}
以下是使用 Hook 的组件:
function App() {
const [formValue, Form, setFormValue] = useForm("San Francisco, CA", "Location");
return (
<Fragment>
<h1>{formValue}</h1>
<Form />
</Fragment>
);
}
虽然Kais的答案将解决症状,但它不会解决原因。 如果有多个输入,它也会失败 - 那么哪一个应该自动聚焦于重新渲染?
当您在另一个函数的作用域内定义一个组件(FormComponent
(时,就会发生此问题,该函数称为App
组件的每个渲染。这在每次重新渲染App
组件并调用useState
时都会为您提供一个全新的FormComponent
。然后,这个新组件就没有重点了。
就个人而言,我会反对从钩子中返回组件。相反,我会定义一个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
];
}
// App.js
import useForm from "./useForm";
export default function App() {
const [formValue, Form] = useForm("San Francisco, CA", "Location");
return (
<>
<h1>{formValue}</h1>
{Form}
</>
);
}
这是一个沙盒
当您在输入框中输入任何文本时。父组件也在重新渲染。因此,您需要手动将重点放在输入上。 为此,请在输入标签中使用autoFocus
<input
type="text"
id={label}
value={state}
placeholder={label}
onChange={e => setState(e.target.value)}
autoFocus
/>
上面的答案对我不起作用。对我有用的解决方案要简单得多,因此不太明显。
问题从本质上讲,我随输入更改的值也用于输入列表中的每个key
。
因此,当我更新值时,key
会发生变化,React 会检测到它相对于最后一个键不同,并在其位置创建一个新输入。作为一个新的输入,它不会专注于自己。
但是,通过使用autoFocus
它将自动关注新创建的输入。但是这个问题并没有得到解决,因为很明显,输入不断经历一个不聚焦和专注的循环。
这是一篇演示该问题的文章。
修复
将key
更新为不可更改的值,以便 React 对列表项具有稳定的引用。就我而言,我只是将其更新为索引。这并不理想(React 文档建议使用稳定的 ID(,但在我的情况下没关系,因为项目的顺序不会改变。
第一个解决方案实际上对我有用,最初包含文本字段的功能组件是主要功能组件的一部分,我遇到了同样的问题,但是当我将文本字段组件提取到另一个页面并导入它时,它工作正常 这是我的组件
<Paper >
<div>
<div style={{padding:'10px' ,display:'flex'}} >
<inputstyle={{marginRight:'5px'}} value={val} onChange={(e)=>{setVal(e.target.value)}} />
</div>
</div>
</Paper>
我在使用样式化组件时遇到了这个问题,问题是每次对输入进行更改时,样式化组件都会更改类,并且类更改使组件重新渲染。
解决方案是像这样在函数组件外部声明样式化组件。
const FormButton = styled.button``
export default function Button(){
return(
<FormButton>Log In</FormButton>
)
我在多个输入(可重用的自定义组件(方面遇到了类似的问题,我只是简单地在输入中添加了键,它解决了我的问题。即使有多个输入,这也将解决您的问题。 (这是由于父组件的重新渲染而发生的,因为当 react 重新渲染时,它不知道哪个输入有焦点,因为它没有这些输入中的键来识别哪个输入有焦点。 请不要永远不要添加 rand(( 函数作为密钥 ID(对于新手(
**例如,由于错误的键道具而导致的焦点错误代码**
return(
<CustomInput key={rand()} placeHolder="email" type="email" data=
{onChangeHandler}/>
<CustomInput key={rand()} placeHolder="password" type="password"
data=
{onChangeHandler}/>
<CustomInput key={rand()} placeHolder="name" type="name" data=
{onChangeHandler}/>
<CustomInput key={rand()} placeHolder="age" type="age" data=
{onChangeHandler}/>
)
上述代码的解释。子组件(自定义输入组件有一个useState,当用户在输入中输入时,更改处理程序使用在每次击键时执行,这导致父组件重新渲染,并且React在重新渲染后变得混乱,因为错误的键道具(rand((产生了新的键道具,这些键道具与以前的键道具不同,这使得反应变得混乱,因此焦点消失了(
波纹管是正确的代码
return(
<CustomInput key="id1" placeHolder="email" type="email" data=
{onChangeHandler}/>
<CustomInput key="id2" placeHolder="password" type="password"
data=
{onChangeHandler}/>
<CustomInput key="id3" placeHolder="name" type="name" data=
{onChangeHandler}/>
<CustomInput key="id4" placeHolder="age" type="age" data=
{onChangeHandler}/>
)
以上代码说明现在将密钥更改为固定 id 后, React 会知道在重新渲染父计算机后将焦点放回正确的输入上,因为键属性(例如"id1"(在重新渲染后将相同