Reputation: 159
I am trying to use a hook to create a textbox that provides the value state as part of the hook.
However, I am not quite successful, as the textbox keeps losing focus whenever I tried to type.
This probably makes more sense if I show what I am doing.
Please see this Codepen for a quick demo. (https://codepen.io/david_yau/pen/RwWVoKz?editors=1111)
Detail explaination
// 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];
}
This way won't work because each time I typed in the textbox, the focus will be lost.
However, if I change the implementation to the following it will work.
The difference between this implementation is that the one above is rendering a new TextBox with <TextBox />
. While the bottom one is using a rendered Textbox instead like {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];
}
If it helps at all, I got this idea from this course: https://frontendmasters.com/courses/complete-react-v5/, around the "Custom Hook" session.
Just to reiterate the question since this is quite a long post. I am wondering why does the first approach does not work because it keeps losing focus, while the second one does.
Upvotes: 0
Views: 870
Reputation: 22304
Because const TextBox = () => <input />
will create a different React component every time useTextBoxTwo()
is called, while const TextBox = <input />
is just a React element, rendered in the same Component (in App
).
In the current implementation, when the element inside a component changes, ReactDOM checks whether it has the same element name (e.g. "input") and doesn't have a different key
- when true, it re-uses the same DOM element, e.g. following 2 React-elements will reuse the same DOM-element (not losing focus):
{condition ? <input value="a" /> : <input value="b" />}
But 2 different React Components will trigger unmounting of the old one, removing it from DOM, and mounting of the new one, creating a new DOM element (=> losing focus).
So, don't create components inside custom hooks, create custom components that use hooks.
Upvotes: 2