React - Loosing focus on input in child components

Hello everyone,

I’m facing an issue with the focus of the input fields. I refactored the following program to separate the logic into modules. When everything was in the root App without components, the inputs didn’t lose focus. However, after componentizing them, they lose focus after typing a character, and I can’t seem to find a solution. Any help would be greatly appreciated.

Thanks!
Federico.

import React, { useState } from "react";

const App = () => {
  const [persons, setPersons] = useState([
    { id: 1, name: "Arto Hellas", number: "040-123456" },
    { id: 2, name: "Ada Lovelace", number: "39-44-5323523" },
    { id: 3, name: "Dan Abramov", number: "12-43-234345" },
    { id: 4, name: "Mary Poppendieck", number: "39-23-6423122" },
  ]);
  const [newName, setNewName] = useState("");
  const [newNumber, setNewNumber] = useState("");
  const [newFilter, setNewFilter] = useState("");
  const [showAll, setShowAll] = useState(true);

  const handleNameChange = (event) => setNewName(event.target.value);
  const handleNumberChange = (event) => setNewNumber(event.target.value);
  const handleFilterChange = (event) => {
    setNewFilter(event.target.value);
    if (newFilter === "") {
      setShowAll(true);
    } else {
      setShowAll(false);
    }
  };

  const addName = (event) => {
    event.preventDefault();
    if (persons.map((person) => person.name).includes(newName)) {
      alert("The name has already been entered.");
    } else {
      setPersons([
        ...persons,
        {
          id: persons.length + 1,
          name: newName,
          number: newNumber,
        },
      ]);
    }
    setNewName("");
    setNewNumber("");
  };

  const personsToShow = showAll
    ? persons
    : persons.filter((person) => {
        const regexFilter = new RegExp(newFilter.toLowerCase());
        const nameLowerCase = person.name.toLowerCase();
        return regexFilter.test(nameLowerCase);
      });

  const Filter = ({ newFilter }) => {
    return (
      <div>
        filter shown with
        <input
          value={newFilter}
          onChange={handleFilterChange}
        />
      </div>
    );
  };

  const PersonForm = ({
    addName,
    handleName,
    handleNumber,
    newName,
    newNumber,
  }) => {
    return(
      <div>
      <form onSubmit={addName}>
      <div>
        name: <input value={newName} onChange={handleName} />
      </div>
      <div>
        number: <input value={newNumber} onChange={handleNumber} />
      </div>
      <div>
        <button type="submit">add</button>
      </div>
    </form>
    </div>
    )
  };

  const Persons = () => {
    return(
      <div>
        {personsToShow.map((person) => (
        <React.Fragment key={person.id}>
          {person.name} {person.number}
          <br />
        </React.Fragment>
      ))}
      </div>
    );
  };

  return (
    <div>
      <h2>Phonebook</h2>
      <Filter newFilter={newFilter} />
      <h2>Add a new</h2>
      <PersonForm
        addName={addName}
        handleName={handleNameChange}
        handleNumber={handleNumberChange}
        newName={newName}
        newNumber={newNumber}
      />
      <h2>Numbers</h2>
      <Persons/>
    </div>
  );
};

export default App;

Github: https://github.com/fedefagundez/fullstackcourse-university-helsinki/tree/main/part2/phonebook

You should not have component definitions inside other component definitions.

If the component needs handlers or state from the parent component you should pass them down using props. Otherwise, the component should have the state and handlers defined inside it (co-located to the component that needs them).

1 Like

¡Thank your very much!

1 Like

Happy to help.

It is an easy mistake to make (many people learning React do it). React doesn’t care nor do the linters (or anything as far as I know). It really should be a warning or something but maybe there are technical reasons why they can’t do that.

2 Likes

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.