Man-Kit Yau
Man-Kit Yau

Reputation: 159

React, using Hooks to create component

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

Answers (1)

Aprillion
Aprillion

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

Related Questions