Home > Blockchain >  Getting data to be fetched upon page render ReactJS
Getting data to be fetched upon page render ReactJS

Time:03-02

Still a newbie, so not sure how to solve this issue. The app gets data about movie genres from an API, it then uses those genres to create options in the drop-down selector. The user can choose a type (tv show or movie) and then the genre. When they hit search it will return a random movie or show in the genre. The starting values are tv show and action. I want the user to be able to immediately hit search and find a title to watch. My problem is the data about movies/ shows in the specified type and genre are only fetched when the user changes the selector option from the default one. You can see this hosted on GH Pages here or check the GH repository

So I want the data from the full_url to be fetched upon render. The feedback from the console is that upon render chosenType and chosenGenre are undefined in the fetch method fetchMovieList(). But once I change the type, an array of movies or shows are fetched.

Any help or advice would be appreciated.

Below is the code.

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

export const MovieContext = createContext({});

export function MovieProvider({ children }) {
  const [movieList, setMovieList] = useState([]);
  const [randomMovie, setRandomMovie] = useState({});
  const [hasMovie, setHasMovie] = useState(false);
  const [genreOptions, setGenreOptions] = useState([]);
  const [chosenGenre, setChosenGenre] = useState();
  const [typeOptions, setTypeOptions] = useState([]);
  const [chosenType, setChosenType] = useState();

  const api = "api_key=3fa371d07ffd6838dc488ff081631c5d";

  const genres_url =
    "https://api.themoviedb.org/3/genre/movie/list?api_key=3fa371d07ffd6838dc488ff081631c5d&language=en-US";

  const types = [
    { type: "TV Show", value: "tv" },
    { type: "Movie", value: "movie" },
  ];


  //fetching genres from API to use in selector and for searching and setting types for selector
  const fetchGenres = () => {
    fetch(genres_url)
      .then((res) => res.json())
      .then((data) => {
        setChosenGenre(data.genres[0].id);
        setGenreOptions(data.genres);
        setTypeOptions(types);
        setChosenType(types[0].value);
        console.log(data);
      });
  };

  //getting genres when page loads 
  useEffect(() => {
    fetchGenres();
  }, []);

    //setting the value of slelector drop downs
    const onChangeGenre = (e) => {
      setChosenGenre(e.target.value);
    };
  
    const onChangeType = (e) => {
      setChosenType(e.target.value);
    };

  //fetching movies or shows from the selected genre
  const full_url = `https://api.themoviedb.org/3/discover/${chosenType}?${api}&with_genres=${chosenGenre}`;

  const fetchMovieList = () => {
      fetch(full_url)
      .then((res) => res.json())
      .then((data) => {
        setMovieList(data.results);
        console.log(data.results);
      });
  };

  console.log(chosenType, chosenGenre)


  //fetches data from API when type or genre is changed
  useEffect(() => {
    fetchMovieList();
  }, [chosenType, chosenGenre]);


  //function that selects a random movie or show from the already fetched data
  const getRandomMovie = (e) => {
    e.preventDefault();
    const randomItem = movieList[Math.floor(Math.random() * movieList.length)];
    setRandomMovie(randomItem);
    console.log(randomItem);
    setHasMovie(true);
  };

  //passing state and functions to child components
  return (
    <MovieContext.Provider
      value={{
        getRandomMovie,
        onChangeGenre,
        onChangeType,
        randomMovie,
        hasMovie,
        genreOptions,
        chosenGenre,
        typeOptions,
        chosenType,
        types,
      }}
    >
      {children}
    </MovieContext.Provider>
  );
}

CodePudding user response:

The problem is here:

//fetches data from API when type or genre is changed
useEffect(() => {
  fetchMovieList();
}, [chosenType, chosenGenre]);

The useEffect hook will be called every time the dependencies change, but also on the initial render of the component. At first, the chosenType and chosenGenre will still be their initial value null. You can fix it with a simple fix like this:

//fetches data from API when type or genre is changed
useEffect(() => {
  if(!chosenType || !chosenGenre) return;
  fetchMovieList();
}, [chosenType, chosenGenre]);

CodePudding user response:

You can try setting the selected attribute to the dropdown, as shown below. Then your api will have the values to make the request, when the page loads.

Note : This will set the last iterating option as the selected value.

Form.js

<form className={classes["form-row"]} onSubmit={getRandomMovie}>
  <p className={classes.label}>Type: </p>
  <select value={chosenType} onChange={onChangeType}>
    {typeOptions.map((type) => (
      <option key={type.value} value={type.value} selected> // <== Here
        {type.type}
      </option>
    ))}
  </select>
  <p className={classes.label}>Genre: </p>
  <select value={chosenGenre} onChange={onChangeGenre}>
    {genreOptions.map((option) => (
      <option key={option.id} value={option.id} selected> // <== Here
        {option.name}
      </option>
    ))}
  </select>
  <button>Search</button>
</form>;
  • Related