Home > Back-end >  How can call two API with condition in react js?
How can call two API with condition in react js?

Time:10-22

I'm in the learning phase so please let me know if something feels illogical. I have been trying to use show result in a way that by default a user should see the trending API results and when he starts searching the other API with search query will trigger or get called. I tried to use if-else but there is no result. It shows the blank. I do not know how can I achieve it. Would really appreciate it if you can help me with this.

when I get the data I am displaying that data in the card below as you will see using the map function, and if the search is blank am trying to show the error. but I am getting a blank card as you can see in the image. how can I also fix this?

enter image description here

Please see the code I have tried. I do not know if it is the logical way or not. Thanks a million in advance.

import React ,{useEffect, useState} from 'react';
import {Grid, Button, Card, CardActionArea, CardActions, CardContent, CardMedia, Typography, makeStyles } from '@material-ui/core';
import Rating from '@material-ui/lab/Rating';
import Watchlist from '../Products/Watchlist.jsx';
import Error from '../Error/Error.jsx';


const useStyles = makeStyles (theme => ({
    cardButton:{
        '&:hover':{
           backgroundColor:'#356E44',
           color: 'white',
        }
    },
Main:{
    width: "100vw",
    justifyContent: " flex-start",
    display: "flex",
    flexWrap: "wrap",
    alignItems: "stretch", 
    alignContent: " flex-start",
    columnGap: "20px",
    rowGap:"5px",
},
cardMain:{
    width: 'min-content',
    height: 'min-content',
    margin: '10px',
    '&:hover':{
        boxShadow: '5px 3px 5px white',
     }
},

cardImage:{
    height: '150px',
    marginLeft: '7px',
    marginRight: '7px',
    marginTop: '5px',
    objectFit: 'cover',
},
cardContent: {
    width: '250px',
    height: '50px',
    wordBreak: 'break-word',
    fontSize: '1rem',
    fontWeight: 'bolder',
},
typography1:{
    float: 'right',
   
},
typography2:{
    float: 'left',
},
}));


const Produts = (props) =>{
    

const classes = useStyles();

const [movieData, setMovieData] = useState([]);
 
 const [watchlist, setWatchlist] = useState ([]);

 const filterData = ((val) => {

     const keyword = props.searchText;

     if (keyword !== "") {
         return val
     } 
     else if (val.original_title?.toLowerCase().includes(props.searchText?.toLowerCase())) {
         return val
     } 
     
  } );


   




useEffect (()=> {
    const getMovieList  = async () => {
        const TrendingUrl = 'https://api.themoviedb.org/3/trending/all/day?api_key=API_keyID' ;
        
        const allResultsUrl = `http://api.themoviedb.org/3/search/movie?api_key=API_keyID&query=${props.searchText}`;
             
        const response = await fetch (props.searchText ? TrendingUrl : allResultsUrl);
                try {
                    const responseJson = await response.json();
                    const data = (responseJson.results);
                    setMovieData(data);
                    console.log(data)
                } catch (err) {
                    console.error(err);
                }
        
    };
 getMovieList();

 

 }, [props.searchText]);


 const handleWatchlist = (movieData) => {
     const newWatchlist = [...watchlist , movieData];
     setWatchlist (newWatchlist);
    }

return (
    <> 
        <Grid
        item
        xs
        container
        direction="column"
        justifyContent="flex-start"
        alignItems="flex-start"
        style={{ backgroundColor: "black", width: "100%", height: "100%"}}
        >
            <div  className ={classes.Main} > { movieData.length === 0 ? (<h1 style = {{color: 'red', fontSize : "2rem"}}>No search results found</h1>)
                : movieData.filter(filterData).map((movie) =>{
                return(
                    <Card className={classes.cardMain}  key={movie.id}>
                <CardActionArea>
                    <CardMedia className = {classes.cardImage}>
                        <img style = {{width: '100%', height: '100%', objectFit: 'cover'}} 
                            src ={`https://image.tmdb.org/t/p/original${movie.poster_path}`} 
                            alt = "movie poster"/>
                    </CardMedia>
                    <CardContent className = {classes.cardContent}>
                        <Typography>  {movie.original_title} </Typography>
                        <Typography 
                                    className = {classes.typography1} 
                                    variant="body2" 
                                    component = "p"
                            > {movie.release_date} 
                            </Typography>
                        <Rating 
                                className = {classes.typography2} 
                                name = "ratings"
                                value =  {movie.vote_average/2} 
                                precision={0.5}
                                readOnly                                
                        />  
                        
                    </CardContent>
                </CardActionArea>
                <CardActions style = {{justifyContent: 'space-evenly'}} >
                    <Button className = {classes.cardButton} size = "small">Watch</Button>
                    <Button className = {classes.cardButton} size = "small" >Share</Button>
                    <Button className = {classes.cardButton}size = "small" onClick = { () => handleWatchlist(movie) }> Add </Button> 
                </CardActions>
               
            </Card>
                );
                
            })}
        
            </div>
        </Grid>
          
    </>
)
};

export default Produts;

CodePudding user response:

I will split the API into two. Also, renamed the variables a bit for a better naming convention.


const fetchTrending = () => {
  const url = 'https://api.themoviedb.org/3/trending/all/day?api_key=api_keyID';
  fetch(url)
    .then(response => response.json())
    .then(trendingMovies => setMovies(trendingMovies))
    .catch(error => {
      // TODO: Do your error handling here
      console.error(error);
    });
};

const fetchQuery = search => {
  const url = `http://api.themoviedb.org/3/search/movie?api_key=api_keyID&query=${search}`;
  fetch(url)
    .then(response => response.json())
    .then(queriedMovies => setMovies(queriedMovies))
    .catch(error => {
      // TODO: Do your error handling here
      console.error(error);
    });
};

/* When the component is mounted, load trending movies
   This will only run once.
*/
useEffect(() => fetchTrending(), []);

// pass this handler to the onChange listener of your search field
const handleSearchChange = search => fetchQuery(search);

CodePudding user response:

I think this might help you. I'm using this little hook a lot for stuff like this.

It works the same as useMemo, but allows you to pass a callback that return a promise rather than immediately returning a value.

Use it like this:

import { usePromiseMemo } from 'usePromiseMemo';

function MyComponent() {
  const movieData = usePromiseMemo(
    () =>
      fetch(
        props.searchText
          ? `http://api.themoviedb.org/3/search/movie?api_key=api_keyID&query=${props.searchText}`
          : `https://api.themoviedb.org/3/trending/all/day?api_key=api_keyID`
      )
        .then(r => r.json())
        .then(r => {
          console.log('Raw data: ', r);
          const data = r.results;
          console.log('Data: ', data);
          return data;
        })
        .catch(err => {
          console.log(err);
        }),
    [props.searchText]
  );

  return <></>;
}

Also, what do you get from the "Raw data"-log?

  • Related