我正在尝试使用一个钩子来创建一个文本框,该文本框将值状态作为钩子的一部分提供。
但是,我并不是很成功,因为每当我尝试键入时,文本框都会失去焦点。
如果我展示自己在做什么,这可能更有意义。
请参阅此Codepen进行快速演示。 (https://codepen.io/david_yau/pen/RwWVoKz?editors=1111)
详细说明
// My first attempt
// App.jsx, the App
const App = () => {
const [text, TextBox] = useTextBox();
return (
<div>
<TextBox />
<p>
text: {text}
</p>
</div>
)
}
// useTextBox.jsx
const useTextBox = () => {
const [text, setText] = React.useState("");
const onChange = (event) => {
setText(event.target.value);
}
const TextBox = () => {
return (
<input type="text" value={text} onChange={onChange} />
)
};
return [text, TextBox];
}
这种方式行不通,因为每次我在文本框中键入内容时,焦点都会丢失。
但是,如果我将实现更改为以下内容,它将起作用。
此实现之间的区别在于,上面的实现是使用<TextBox />
渲染一个新的TextBox。而最底层的是使用渲染的文本框,例如{TextBox}
。
// App.jsx
const App = () => {
const [text, TextBox] = useTextBoxOne();
return (
<div>
<h1> This one work </h1>
{TextBox}
<p>
text: {text}
</p>
</div>
)
}
// useTextBox.jsx
const useTextBox = () => {
const [text, setText] = React.useState("");
const onChange = (event) => {
setText(event.target.value);
}
const TextBox = (
<input type="text" value={text} onChange={onChange} />
);
return [text, TextBox];
}
如果有帮助,我从本课程中得到了这个主意:https://frontendmasters.com/courses/complete-react-v5/,在“自定义挂钩”会议上。
仅重申一个问题,因为这是一篇很长的文章。我想知道为什么第一种方法不起作用,因为它会不断失去关注,而第二种方法却不能。
因为每次调用const TextBox = () => <input />
时useTextBoxTwo()
都会创建一个不同的React组件,而const TextBox = <input />
只是一个React元素,呈现在同一Component(在App
中)。
在当前实现中,当组件内的元素发生更改时,ReactDOM会检查它是否具有相同的元素名称(例如“ input”)并且没有不同的key
-如果为true,它将重复使用相同的元素DOM元素,例如以下2个React元素将重用相同的DOM元素(不失去焦点):
{condition ? <input value="a" /> : <input value="b" />}
但是2个不同的React组件将触发旧组件的卸载,将其从DOM中删除,并安装新组件,从而创建新的DOM元素(=>失去焦点)。
因此,请勿在自定义钩子内创建组件,而应创建使用钩子的自定义组件。
因为每次调用const TextBox = () => <input />
时useTextBoxTwo()
都会创建一个不同的React组件,而const TextBox = <input />
只是一个React元素,呈现在同一Component(在App
中)。