Home > Blockchain >  Losing focus on input onChange React
Losing focus on input onChange React

Time:07-04

What I'm trying to achieve, it's to create each input as own component. And I can't get how to fix thing when my app all the time rerendering when I'm pressing any key. I know if I'll use controlledInputs -> so each input would have it own useState that would work. But the main idea to do that this way

import React, { useState } from 'react';
const ControlledInputs = () => {
  
  const [person, setPerson] = useState({ firstName: '', email: '', age: '' });
  const [people, setPeople] = useState([]);
  const handleChange = (e) => {
    const name = e.target.name;
    const value = e.target.value;
    setPerson({ ...person, [name]: value });
  };
  const handleSubmit = (e) => {
    e.preventDefault();
    if (person.firstName && person.email && person.age) {
      const newPerson = { ...person, id: new Date().getTime().toString() };
      setPeople([...people, newPerson]);
      setPerson({ firstName: '', email: '', age: '' });
    }
  };
   function FormControl({number, idname , type , text}){
    return(
      <div className='form-control'>
        <label htmlFor={idname}>{text} : </label>
        <input
          type={type}
          id={idname}
          name={idname}
          value={person[idname]}
          onChange={(e) =>handleChange(e)}
        />
      </div>
    )
  }
 
  return (
    <>
      <article className='form'>
        <form>
          <FormControl idname={"firstName"} type={"text"} text={"First name"}/>
          <FormControl type={"email"} idname={"email"} text={"Email"}/>
          <FormControl type={"age"} idname={"age"} text={"Age"}/>
          <button type='submit' className='btn' onClick={handleSubmit}>
            add person
          </button>
        </form>
      </article>
      <article>
        {people.map((person) => {
          const { id, firstName, email, age } = person;
          return (
            <div key={id} className='item'>
              <h4>{firstName}</h4>
              <p>{email}</p>
              <p>{age}</p>
            </div>
          );
        })}
      </article>
    </>
  );
};

export default ControlledInputs;

CodePudding user response:

You need to define the FormControl outside of ControlledInputs, otherwise, React will recreate it and you lose focus as well as data.

And you need to pass value and handleChange as props in FormControl.

Here are codes you can refactor. Please note that the number you defined is not removed.

function FormControl({value, handleChange, idname , type , text}){
  return(
    <div className='form-control'>
      <label htmlFor={idname}>{text} : </label>
      <input
        type={type}
        id={idname}
        name={idname}
        value={value}
        onChange={(e) =>handleChange(e)}
      />
    </div>
  )
}

Usage in form:

function FormControl({value, handleChange, idname , type , text}){
  return(
    <div className='form-control'>
      <label htmlFor={idname}>{text} : </label>
      <input
        type={type}
        id={idname}
        name={idname}
        value={value}
        onChange={(e) =>handleChange(e)}
      />
    </div>
  )
}

const ControlledInputs = () => {
  
  const [person, setPerson] = useState({ firstName: '', email: '', age: '' });
  const [people, setPeople] = useState([]);
  const handleChange = (e) => {
    const name = e.target.name;
    const value = e.target.value;
    setPerson({ ...person, [name]: value });
  };
  const handleSubmit = (e) => {
    e.preventDefault();
    if (person.firstName && person.email && person.age) {
      const newPerson = { ...person, id: new Date().getTime().toString() };
      setPeople([...people, newPerson]);
      setPerson({ firstName: '', email: '', age: '' });
    }
  };
   
 
  return (
    <>
      <article className='form'>
        <form>
          <FormControl idname={"firstName"} type={"text"} text={"First name"} value={person['firstName']} handleChange={handleChange}/>
          <FormControl type={"email"} idname={"email"} text={"Email"} value={person['email']} handleChange={handleChange}/>
          <FormControl type={"age"} idname={"age"} text={"Age"} value={person['age']} handleChange={handleChange}/>
          <button type='submit' className='btn' onClick={handleSubmit}>
            add person
          </button>
        </form>
      </article>
      <article>
        {people.map((person) => {
          const { id, firstName, email, age } = person;
          return (
            <div key={id} className='item'>
              <h4>{firstName}</h4>
              <p>{email}</p>
              <p>{age}</p>
            </div>
          );
        })}
      </article>
    </>
  );
};

CodePudding user response:

That is because FormControl is defined inside the ControlledInputs component. So, on each rerender of the ControlledInputs, you create a new FormControl function and that means that React will treat it as a different component than the one in the previous render, and so it will lose focus, as the old one is considered unmounted.

Just define the FormControl outside the other one, and pass it what extra data you need as props, and you should be set.

  • Related