Home > OS >  How to pass state from one component to another in React
How to pass state from one component to another in React

Time:09-16

I'm currently working on a movie type app and fetching data from an API. I've made two separate components in my react project:

component one : Hero that displays movie poster

component two : Slider that displays all of the movies.

I've added a state variable to update the hero movie poster when each individual movie from the slider is clicked.

Originally, I had both components as the same component and that worked fine. I decided to separate them as I wanted to reuse the slider with another movie genre without having another hero section.

My question is how do I pass the setSelectMovie state variable from the HeroSlider to the Slider component to update the hero when a movie from the slider is clicked.

I have attached some references, thanks

import React from 'react'
import HeroSlider from '../components/HeroSlider';
import Slider from '../components/Slider'


function Movies({movies, topMovies, TvShows}) {


  
    return (

        <>

           <HeroSlider items={movies} />

           <Slider items={movies} />
           <Slider items={topMovies} />
           
        </>
    );
  }

  export default Movies

import React, {useState }from 'react';
import FilterButton from './FilterButton';



function HeroSlider({items}) {


//state 
const [selectMovie, setSelectMovie] = useState(items.at(10));

   
   
return (

<>

    {/* Hero Section */}

        
    <div className="hero">


        <div className="bg-image">
            <img src={'https://image.tmdb.org/t/p/w500'   selectMovie.backdrop_path} className="banner-img" />
        </div>

        <div className="movie-details">
            <h1>{selectMovie.original_title}</h1>
            <p>{selectMovie.overview}</p> 
            <button className='trailer-btn'>Watch Trailer</button>
        </div>
        
    </div>




{/*Originally had the slider here before breaking off into a seperate component (This Worked) */}

{/* 



<div className="media-scroller snaps-inline">
    
    {items.map((image, index) => (

                
        

        <div className="media-element">
            <img src={'https://image.tmdb.org/t/p/w500'   image.poster_path} onClick={()=>{setSelectMovie(image)}} />
        </div>

   

   ))}
   </div>  */}

 


</>

    );
}


export default HeroSlider;

import React, {useState }from 'react';



function Slider ({items}) {

   
   
return (

<>


    <h3 className='movie-genre'>Picked For You</h3>

        <div className="media-scroller snaps-inline">
    
    {items.map((image, index) => (



        <div className="media-element">
            <img src={'https://image.tmdb.org/t/p/w500'   image.poster_path} onClick={()=>{setSelectMovie(image)}} />
        </div>

   

   ))}
   
   </div>



</>

    );
}


export default Slider;

CodePudding user response:

The fastest solution will be to use a Context Provider and share the setSelectMovie.

You wrap the components that need to share the Context and you are ready to go!:

Ref: Context Provider

CodePudding user response:

"Lift state up." Basically, since the state is shared by these sibling components, it belongs in the parent component. So Movies would host the state:

const [selectMovie, setSelectMovie] = useState();

Then these variables (the state value and its setter) can be passed as props to the child components:

<HeroSlider items={movies} selectMovie={selectMovie} setSelectMovie={setSelectMovie} />
<Slider items={movies} selectMovie={selectMovie} setSelectMovie={setSelectMovie} />
<Slider items={topMovies} selectMovie={selectMovie} setSelectMovie={setSelectMovie} />

They would then accept it as a prop:

function HeroSlider({items, selectMovie, setSelectMovie}) {

and:

function Slider ({items, selectMovie, setSelectMovie}) {

So any call to setSelectedMovie in a child component would update the state in the parent component, triggering a re-render of that parent and any child relying on that state.

Obviously if any given component doesn't use one of these two values then you don't need to pass both, just the one(s) it will use.


As you can see, this does start to make the code look a bit clogged up by repeating these values. You can make use of higher-level state management systems as needed/preferred to abstract application-wide state away from individual components. useContext or external systems like Redux are common approaches.

In those cases, the state itself exists outside of the component using it and each component which needs that state (the value and/or the setter) would use a hook to pull what it needs from that more global state.

  • Related