otto
otto

Reputation: 2033

React input lose focus when typing

I dont understand why the input loses focus after typing one character when the component is defined inside an other component. I read in other answers to use ref. But it does not work.

Does not work:

import React, { useState, useRef } from "react";
import ReactDOM from "react-dom";


function MyApp() {
  const [text1, setText1] = useState("");
  const [text2, setText2] = useState("");
  const ref1 = useRef(null)
  const ref2 = useRef(null)

  const TextInput = ({ref, text, onChange }) => {
    return <input ref={ref} defaultValue={text} onChange={onChange} />;
  };
  

  const onChange1 = e => {
    setText1(e.currentTarget.value);
  };

  const onChange2 = e => {
    setText2(e.currentTarget.value);
  };
  return (
    <form className="App">
      <TextInput ref={ref1} text={text1} onChange={onChange1} />
      <TextInput ref={ref2} text={text2} onChange={onChange2} />
    </form>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<MyApp />, rootElement);

When I define the compoent outside everything works fine.

Does work:

import React, { useState, useRef } from "react";
import ReactDOM from "react-dom";


const TextInput = ({ref, text, onChange }) => {
  return <input ref={ref} defaultValue={text} onChange={onChange} />;
};


function MyApp() {
  const [text1, setText1] = useState("");
  const [text2, setText2] = useState("");
  const ref1 = useRef(null)
  const ref2 = useRef(null)



  const onChange1 = e => {
    setText1(e.currentTarget.value);
  };

  const onChange2 = e => {
    setText2(e.currentTarget.value);
  };
  return (
    <form className="App">
      <TextInput ref={ref1} text={text1} onChange={onChange1} />
      <TextInput ref={ref2} text={text2} onChange={onChange2} />
    </form>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<MyApp />, rootElement);

JS Fiddle

Upvotes: 0

Views: 3420

Answers (1)

rishabh0211
rishabh0211

Reputation: 443

You are recreating TextInput whenever the input value changes and the MyApp component renders. If you want to include TextInput component inside of MyApp component, you can use useCallback hook to prevent the recreation of TextInput when the component renders.

JSFiddle

import React, { useState, useRef, useCallback } from "react";
import ReactDOM from "react-dom";

function MyApp() {
      const [text1, setText1] = useState("");
      const [text2, setText2] = useState("");
      const ref1 = useRef(null);
      const ref2 = useRef(null);

      const TextInput = useCallback(({ ref, text, onChange }) => {
        return <input ref={ref} defaultValue={text} onChange={onChange} />;
      }, []);

      const onChange1 = e => {
        setText1(e.currentTarget.value);
      };

      const onChange2 = e => {
        setText2(e.currentTarget.value);
      };
      return (
        <form className="App">
          <TextInput ref={ref1} text={text1} onChange={onChange1} />
          <TextInput ref={ref2} text={text2} onChange={onChange2} />
        </form>
      );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<MyApp />, rootElement);

Upvotes: 3

Related Questions