reactjsreact-hooksreact-reduxomdbapi

Get input value with react hooks to search on oMdb api


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;

Solution

  • 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