Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React - input loses focus on keypress

I have run into a weird bug with my search input component where it loses focus on every keypress and can't figure out why.

const App = () => {
  let [characters, setCharacters] = useState([]);
  let [filteredCharacters, setFilteredCharacters] = useState([]);
  // more state
  let [search, setSearch] = useState("");

  useEffect(() => {
    setIsLoading(true);
    axios
      .get(`https://swapi.co/api/people/?page=${pageNumber}`)
      .then(res => {
        console.log(res.data.results);
        setCharacters(res.data.results);
        setFilteredCharacters(res.data.results);
      })
      .catch(err => console.error(err))
      .then(() => {
        setIsLoading(false);
      });
  }, [pageNumber]);

  function updatePage(e) {
     // update page
  }

  function handleSearch(e) {
    setSearch(e.target.value);
    const filtered = characters.filter(character => {
      if (character.name.toLocaleLowerCase().indexOf(e.target.value) !== -1) {
        return character;
      }
    });
    setFilteredCharacters(filtered);
  }
  function SearchBar() {
    return (
      <React.Fragment>
        <StyledInput
          type="text"
          id="search"
          value={search}
          placeholder="Search by name..."
          onChange={e => handleSearch(e)}
        />
      </React.Fragment>
    );
  }

  return (
    <React.Fragment>
      <GlobalStyles />
      <div className="App">
        <Heading>React Wars!</Heading>
        <SearchBar />
        <Pagination handleClick={updatePage} />
        {!isLoading && Object.entries(filteredCharacters).length ? (
          <CharacterList characters={filteredCharacters} />
        ) : (
          <LoadingBar />
        )}
      </div>
    </React.Fragment>
  );
};

I'm also getting a Line 65:50: Expected to return a value at the end of arrow function array-callback-return for the characters.filter() line so I don't know if that has to do with it.

If it helps, the deployed app with the bug can be seen here --> https://mundane-vacation.surge.sh

like image 574
Austin Walela Avatar asked Nov 09 '19 11:11

Austin Walela


People also ask

Why does the input field lose focus after typing a character React?

To fix input losing focus when rerendering with React, we should define child components outside the parent component. const Child = () => <p>Child! </p>; const Parent = () => <Child />; to define the Child component outside the Parent .

How do you keep input focused React?

To set focus on an input field after rendering with React, we can assign a ref to the input element with the useRef hook. Then we call focus on the current value of the ref to focus on the input. to call useRef to create a ref and assign it to inputReference . Then we call inputReference.

Why does input lose focus?

input s provided to Fields as their component props are created anew after every keystroke. This causes them to lose focus, despite having an unique, constant key.


1 Answers

You have a problem with focus because your component SearchBar is declared inside App component and it is recreated on each rendering. You need to move SearchBar out of App or just move StyledInput on the place of SearchBar. If you choose the first way, I recommend you remove React.Fragment from SearchBar, because it has only one rendered child:

function SearchBar(props) {
    return (
        <StyledInput
          type="text"
          id="search"
          value={props.value}
          placeholder="Search by name..."
          onChange={props.onChange}
        />
    );
  }

And in App:

<SearchBar onChange={handleSearch} value={search} />

To fix your warning, you need always return a boolean value inside the filter function. Now you return nothing (i.e. undefined) in case if the character does not pass the condition. So change your filter function like this:

const filtered = characters.filter(character => {
    return character.name.toLocaleLowerCase().indexOf(e.target.value) !== -1
});
like image 194
Andrii Golubenko Avatar answered Oct 21 '22 17:10

Andrii Golubenko