skip to Main Content

I have been working on an SPA with React 18 and The Movie Database (TMDB) API.

I am currently working on a search functionality.

In the Searchbox.jsx component I have:

import { ReactComponent as Magnifier } from '../../icons/magnifier.svg';
import { useEffect, useState } from 'react';
import axios from 'axios';

function Searchbox({ movie }) {

  const API_URL = 'https://api.themoviedb.org/3';
  const [searchInput, setSearchInput] = useState('');
  const [results, setResults] = useState([]);
  const timeOutInterval = 1000;

  const doMovieSearch = async (e) => {
    setSearchInput(e.target.value);

    if (searchInput >= 3) {
      const { data: { results } } = await axios.get(`${API_URL}/search/movie?query=${this.searchInput}`, {
        params: {
          api_key: process.env.REACT_APP_API_KEY
        }
      });

      setResults(results);
      console.log(results);
    }
  }

  const debounceMovieSearch = () => {
    setTimeout(doMovieSearch, timeOutInterval)
  }

  return (
    <form className="search_form w-100 mx-auto mt-2 mt-md-0">
      <div className="input-group">
        <input className="form-control search-box" type="text" value={searchInput} onKeyUp={debounceMovieSearch} placeholder="Search movies..." />
        <div className="input-group-append">
          <button className="btn" type="button">
            <Magnifier />
          </button>
        </div>
      </div>
    </form>
  );
}

export default Searchbox;

The problem

For a reson I have been unable to figure out, doing a search fails with this error:

Cannot read properties of undefined (reading ‘target’).

The error is at the line setSearchInput(e.target.value).

The line console.log(results) does not log anything.

Questions

  1. What am I doing wrong?
  2. What is the most reliable way to fix this issue?

2

Answers


  1. Try to change from onKeyUp to onChange

    import { ReactComponent as Magnifier } from '../../icons/magnifier.svg';
    import { useEffect, useState } from 'react';
    import axios from 'axios';
    
    function Searchbox({ movie }) {
    
      const API_URL = 'https://api.themoviedb.org/3';
      const [searchInput, setSearchInput] = useState('');
      const [results, setResults] = useState([]);
      const timeOutInterval = 1000;
    
      const doMovieSearch = async (e) => {
        setSearchInput(e.target.value);
    
        if (searchInput >= 3) {
          const { data: { results } } = await axios.get(`${API_URL}/search/movie?query=${this.searchInput}`, {
            params: {
              api_key: process.env.REACT_APP_API_KEY
            }
          });
    
          setResults(results);
          console.log(results);
        }
      }
    
      const debounceMovieSearch = () => {
        setTimeout(doMovieSearch, timeOutInterval)
      }
    
      return (
        <form className="search_form w-100 mx-auto mt-2 mt-md-0">
          <div className="input-group">
            <input className="form-control search-box" type="text" value={searchInput} onKeyUp={debounceMovieSearch} placeholder="Search movies..." />
            <div className="input-group-append">
              <button className="btn" type="button">
                <Magnifier />
              </button>
            </div>
          </div>
        </form>
      );
    }
    export default Searchbox;
    
    Login or Signup to reply.
  2. To fix this issue, you can use a functional update with setSearchInput to ensure that you’re always using the latest value of searchInput. Here’s the modified code:

    const doMovieSearch = async (e) => {
      const inputValue = e.target.value;
      setSearchInput(inputValue);
    
      if (inputValue.length >= 3) {
        const { data: { results } } = await axios.get(`${API_URL}/search/movie?query=${inputValue}`, {
          params: {
            api_key: process.env.REACT_APP_API_KEY
          }
        });
    
        setResults(results);
        console.log(results);
      }
    }
    
    const debounceMovieSearch = () => {
      setTimeout(() => {
        doMovieSearch({ target: { value: searchInput } }); // Pass a mock event object with the latest searchInput value
      }, timeOutInterval);
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search