본문 바로가기
REACT

[클론코딩] 무비앱 시리즈 #8

by kmyobin 2022. 7. 19.

#8 영화 출연진들 가져오기

 

전에 #5에서 배웠던 Grid를 이용하여 영화 출연진도 똑같은 형태로 출력되게 할 것이다

Toggle Actor View를 누르면 영화 출연진이 나오는 구조이다

 

저번 #7 때 MovieDetail.js에서 endpointCrew라는 변수를 선언한 적이 있다

let endpointCrew = `${API_URL}movie/${movieId}/credits?api_key=${API_KEY}` // 영화 출연진 정보 가져옴

그럼 fetch 구문을 이용하여 영화 출연진들을 가져와보고, 이를 console.log로 찍어보자

    fetch(endpointCrew)
    .then(response => response.json())
    .then(response =>{
      console.log('responseForCrew', response)
    })

cast, crew, id

여기서 우리가 쓸 정보는 cast의 name, profile_path이다

 

useState를 사용하여 배우들의 정보를 받는다

const [Casts, setCasts] = useState([]) // array로 받는다는 뜻

 

그리고 기본적인 형태는 전에 했던 #5 Grid 편과 동일하므로 LandingPage.js에서 

            {/*Movie Grid Cards*/}

            <Row gutter={[16, 16]}>

                {Movies && Movies.map((movie, index) => (
                    <React.Fragment key={index}>
                        <GridCards 
                            image={movie.poster_path ? `${IMAGE_BASE_URL}w500${movie.poster_path}` : null}
                            movieId={movie.id} // 고유의 영화 정보에 들어가기 위해 필요
                            movieName={movie.original_title}
                            
                        />
                    </React.Fragment>
                ))}
            </Row>

이 부분을 복사하여

MovieDetail.js의 {/*Actors Grid*/}에 붙여 넣는다

 

그 다음 수정을 한다

        {/*Actors Grid*/}
        <div style={ {display:'flex', justifyContent:'center', margin:'2rem'} }>
          <button >Toggle Actor View</button>
        </div>

        <Row gutter={[16, 16]}>
          {Casts && Casts.map((cast, index) => (
            <React.Fragment key={index}>
              <GridCards 
                image={cast.profile_path ? `${IMAGE_BASE_URL}w500${cast.profile_path}` : null}
                characterName={cast.name}
                />
            </React.Fragment>
          ))}
        </Row>

이 때 GridCards.js, Row가 필요하므로 import도 잊지 않는다

import GridCards from '../commons/GridCards'
import { Row } from 'antd'

 

아까 GridCards의 기본적인 틀을 쓴다고 했었다

근데 쓰이는 경우가 두가지가 있다

1. LandingPage, 2. Toggle Actor View

그러므로 구분을 하여 출력을 해줘야 한다

 

LandingPage.js로 가서 <GridCards> 내부 제일 첫번째 줄에 코드 하나를 추가한다

<GridCards 
  landingPage
  image={movie.poster_path ? `${IMAGE_BASE_URL}w500${movie.poster_path}` : null}
  movieId={movie.id} // 고유의 영화 정보에 들어가기 위해 필요
  movieName={movie.original_title}
/>

landingPage라는 코드를 추가해준 모습이다

 

다시 GridCards.js로 가서 코드를 수정해준다

function GridCards(props) {
  // columm의 size가 24이므로 lg일 땐 4개, md일 땐 3개, xs일 땐 1개만 보인다
  
  if(props.landingPage){
    return (
    <Col lg={6} md={8} xs={24}> 
      <div style={{position: 'relative'}}>
        <a href={`/movie/${props.movieId}`}>
          <img style={{width:'100%', height: '320px'}} src={props.image} alt={props.movieName} />
        </a>
      </div>
    </Col>
    )
  }
  else{
    return(
      <Col lg={6} md={8} xs={24}> 
        <div style={{position: 'relative'}}>
            <img style={{width:'100%', height: '320px'}} src={props.image} alt={props.characterName} />
        </div>
      </Col>
    )
  }
  
  
}

<a>태그(하이퍼링크 연결)를 없애주고 alt에 있는 이름도 characterName으로 바꿔준다

landingPage면 if문이, 그 이외는 else문이 실행된다

 

그렇게 하고 창을 보면

잘 뜨는 것을 확인할 수 있다

 

하지만 우리가 원하는 것은 Toggle Actor View를 눌렀을 때만 배우 사진들이 보이는 것이다

그러므로 그에 대한 설정을 해준다

 

일단 useState를 이용하여 아래와 같은 코드를 MovieDetail.js에 적어준다

const [ActorToggle, setActorToggle] = useState(false)

 

Toggle Actor View를 클릭해야 이벤트가 발생하므로 

<button onClick={toggleActorView}>Toggle Actor View</button>

위와 같이 적어준다

 

클릭하면 toggleActorView라는 event가 발생하는 것이므로 toggleActorView를 정의해준다

  const toggleActorView = () => {
    setActorToggle(!ActorToggle)
  }

초기값이 false였으므로 !연산자를 붙이면 true가 될 것이다

 

그럼 아까 설정해준 Grid들이 ActorToggle이 true인 경우에만 나타나게 설정하면 된다

        {/*Actors Grid*/}
        <div style={ {display:'flex', justifyContent:'center', margin:'2rem'} }>
          <button onClick={toggleActorView}>Toggle Actor View</button>
        </div>


        {ActorToggle &&
          <Row gutter={[16, 16]}>
            {Casts && Casts.map((cast, index) => (
              <React.Fragment key={index}>
                <GridCards 
                  image={cast.profile_path ? `${IMAGE_BASE_URL}w500${cast.profile_path}` : null}
                  characterName={cast.name}
                  />
              </React.Fragment>
            ))}
          </Row>
        }

 

 

결과창

클릭 전
클릭 후

 

 


 

근데 가끔씩 에러가 뜨면서 사진이 안뜨는 경우가 있었다

그래서 profile_path가 null이면 아예 출력을 하지 않게 코드를 다시 구성해보았다

 

MovieDetail.js을 수정해준다

const [LoadingForCasts, setLoadingForCasts] = useState(true)

 

fetch구문이 있었는데 거기에 setLoadingForCasts를 추가한다

  useEffect(() => {

    // cast정보만 가져올것(crew엔 감독도 있기 때문)
    let endpointCrew = `${API_URL}movie/${movieId}/credits?api_key=${API_KEY}` // 영화 출연진 정보 가져옴
    let endpointInfo = `${API_URL}movie/${movieId}?api_key=${API_KEY}`


    //console.log(props.match)
    fetch(endpointInfo)
    .then(response => response.json())
    .then(response =>{
      //console.log(response)
      setMovie(response)

    })

    fetch(endpointCrew)
    .then(response => response.json())
    .then(response =>{
      console.log('responseForCrew', response)
      setCasts(response.cast)
    })

    setLoadingForCasts(false)
  } , [])

맨 아래에 setLoadingForCasts(false)가 추가된 것을 볼 수 있다

 

그리고 {/*Actors Grid*/}부분을 수정해준다

        {ActorToggle &&
          <Row gutter={[16, 16]}>
            {!LoadingForCasts ? Casts.map((cast, index) => (
              cast.profile_path &&
              //<React.Fragment key={index}>
                <GridCards 
                  image={cast.profile_path ? `${IMAGE_BASE_URL}w500${cast.profile_path}` : null}
                  characterName={cast.name}
                  />
              //</React.Fragment>
            )):
          
            <div>loading...</div>
            }
          </Row>
        }

Loading이 되어야 GridCard를 출력하게 만들었다

 

댓글