1

I want to do a movie search with the oMdb api using React Hooks. The result is not as expected. I seem to break some React Hooks rule that I don't understand.

Here is the code.

HOOK TO SEARCH

The Hook inside of a store. (If I use searchMovies('star wars') in a console.log I can see the result of star wars movies and series.)

import React, { useState, useEffect } from "react";


const useSearchMovies = (searchValue) => {

    const API_KEY = "731e41f";
    const URL = `http://www.omdbapi.com/?&apikey=${API_KEY}&s=${searchValue}`

    // Manejador del estado
    const [searchMovies, setSearchMovies] = useState([])
    //Llamar y escuchar a la api
    useEffect(() => {
        fetch(URL)
            .then(response => response.json())
            .then(data => setSearchMovies(data.Search))
            .catch((error) => {
                console.Console.toString('Error', error)
            })
    }, []);
    return searchMovies;
};


THE INPUT ON A SANDBOX

Here i have the input to search with a console log to see the result.

import React, { useState } from "react";
import searchMovies from "../store/hooks/useSearchMovies";

const Sandbox = () => {


    
    const [search, setSearch] = useState('')   
    const onChangeHandler = e =>{
        setSearch(e.target.value)
        console.log('Search result', searchMovies(search))
    } 

    const handleInput =()=> {
        
        console.log('valor del input', search)
    }
    
    return (
        <div>
            <h1>Sandbox</h1>
            <div>
                <input type="text" value={search} onChange={onChangeHandler}/>
                <button onClick={handleInput()}>search</button>

            </div>
        </div>
    )
}

export default Sandbox;

1 Answers1

0

Issue

You are breaking the rules of hooks by conditionally calling your hook in a nested function, i.e. a callback handler.

import searchMovies from "../store/hooks/useSearchMovies";

...

const onChangeHandler = e => {
  setSearch(e.target.value);
  console.log('Search result', searchMovies(search)); // <-- calling hook in callback
} 

Rules of Hooks

Only call hooks at the top level - Don’t call Hooks inside loops, conditions, or nested functions.

Solution

If I understand your code and your use case you want to fetch/search only when the search button is clicked. For this I suggest a refactor of your useSearchMovies hook to instead return a search function with the appropriate parameters enclosed.

Example:

const useSearchMovies = () => {
  const API_KEY = "XXXXXXX";

  const searchMovies = (searchValue) => {
    const URL = `https://www.omdbapi.com/?apikey=${API_KEY}&s=${searchValue}`;
    return fetch(URL)
      .then((response) => response.json())
      .then((data) => data.Search)
      .catch((error) => {
        console.error("Error", error);
        throw error;
      });
  };

  return { searchMovies };
};

Usage:

import React, { useState } from "react";
import useSearchMovies from "../store/hooks/useSearchMovies";

const Sandbox = () => {
  const [search, setSearch] = useState('');
  const [movies, setMovies] = useState([]);

  const { searchMovies } = useSearchMovies();
  
  const onChangeHandler = e => {
    setSearch(e.target.value)
  };

  const handleInput = async () => {
    console.log('valor del input', search);
    try {
      const movies = await searchMovies(search);
      setMovies(movies);
    } catch (error) {
      // handle error/set any error state/etc...
    }
  }
    
  return (
    <div>
      <h1>Sandbox</h1>
      <div>
        <input type="text" value={search} onChange={onChangeHandler}/>
        <button onClick={handleInput}>search</button>
      </div>

      <ul>
        {movies.map(({ Title }) => (
          <li key={Title}>{Title}</li>
        ))}
      </ul>
    </div>
  );
};

export default Sandbox;

Edit get-input-value-with-react-hooks-to-search-on-omdb-api

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • Gracias @drew Reese es muy muy útil. Mi intención es hacerlo sin el botón de buscar. Ahora intentaré hacerlo. – Isaac Martí Mar 08 '22 at 16:03
  • @IsaacMartí Welcome! Had to run the rest through Google Translate. Yeah, based on that it sounds like you want to move the `handleInput` logic into `onChangeHandler` and pass `e.target.value` directly to the search function. Cheers and good luck! – Drew Reese Mar 08 '22 at 16:16
  • Thanks and Sorry! -_-' – Isaac Martí Mar 08 '22 at 16:17