How to pass api value to useState as its initial value?

Hi experts,

I have been learning react since a week now and I have come across an issue where I want to pass the value to useState and then use that value as default value for my rating component.
Please see the code below :

const Produts = () =>{

    const classes = useStyles();
    
    const [movieData, setMovieData] = useState([
        //the below is an fake api data which needs to be deleted when final disgn is ready and add real api from useEffect
        {
            "adult": false,
            "backdrop_path": "/7RyHsO4yDXtBv1zUU3mTpHeQ0d5.jpg",
            "genre_ids": [
            12,
            878,
            28
            ],
            "id": 299534,
            "original_language": "en",
            "original_title": "Avengers: Endgame",
            "overview": "After the devastating events of Avengers: Infinity War, the universe is in ruins due to the efforts of the Mad Titan, Thanos. With the help of remaining allies, the Avengers must assemble once more in order to undo Thanos' actions and restore order to the universe once and for all, no matter what consequences may be in store.",
            "popularity": 326.894,
            "poster_path": "/or06FN3Dka5tukK1e9sl16pB3iy.jpg",
            "release_date": "2019-04-24",
            "title": "Avengers: Endgame",
            "video": false,
            "vote_average": 8.3,
            "vote_count": 18957
            },
         
    ]);

//here I am trying to pass the vote_average value to useState as its initial value. 
    const ratings = (movieData.vote_average);
    const [ratingValue, setRatingValue] = useState(ratings );

//finally am returning it using map function in rating component below
return (
        <> 
            <div className={classes.main}> 
            {movieData.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 = {ratingValue}
    *//here am trying to render/return that vote_average value and then change when user clicks or selects*
                                onChange = {(event, newRating) => {
                                  setRatingValue(newRating);
                                }}

                           />  
                       </CardContent>
                   </CardActionArea>
                   <CardActions >
                       <Button className = {classes.cardButton} >Watch</Button>
                       <Button className = {classes.cardButton}>Like</Button>
                       <Button className = {classes.cardButton}>Rent</Button>
                   </CardActions>
               </Card>
                 );
                   
            })}
           
            </div>
             
              
        </>
    )
};
export default Produts;

can anyone please let me know what can I do and how ??

Thanks a million in advance.
@DanCouper any help sir ?

movieData is an array, and it looks like you are trying to access a key from it. Try getting the vote_average from the first item in the array?

1 Like

The initial state can’t be async if you’re using useState, so you can’t set the API value as the initial state unless you make the request in a parent component and pass the result in as a prop (in which case you wouldn’t need the useState anyway).

As it is you have to set it as, for example, an empty array first, then in useEffect populate that array on a successful request to the API.

3 Likes

Hi @jonathan.roley
I tried your way to get that on console first and it says undfined.

const ratings = (movieData.vote_average);

    console.log(ratings);

Hi @DanCouper ,

So you mean that if I have to get any value from something I always have to use props in my main function? Just to be clear with concepts sorry if the question is funny.

Hi @DanCouper and @jonathan.roley

So I got the value now but I do not know how should I pass that value to onChange event?

const [ratingValue, setRatingValue] = useState();
<Rating 
                                className = {classes.typography2} 
                                name = "ratings"
                                value =  {movie.vote_average/2} 
                                onChange = {(event, newRating) => {
                                  setRatingValue(newRating);
                                }}

                           />  

No, it’s not a strange question at all.

So you have useState function. It takes one argument, which is the initial value.

That initial value has to be be a constant value, not something that might be a value at some point in the future (ie a promise). So it can’t be async

So currently with what you have set up, you need to have your useState take some default value, which sensibly would be an empty array (the data you’re getting is going to be a populated array).

Then you use the useEffect function to make an async call, and if that completes you update the state with the result of the call.


The other option I mentioned is just moving things around, so you’re still going to have the above, but you split your component up.

You have a parent component that makes an async call, then you pass the result of that (array of stuff) as a prop to a component. That component just renders the list of things that you’ve passed as a prop

You can do it using a custom hook, but I don’t really see a reason for it.

Example code

Not sure just how bad an idea it is to use it for async fetching but it does seem to work just fine.

1 Like

i recommend you watch this video segment where you can see a simple example of fetching data and loading elements using it

1 Like