[React] TMDB movie app

TMDB react movie app


react의 기초를 학습한 후, 배운 것을 실제로 개발하면서 사용해봐야 확실히 이해가 되고 체득하게 되는 것 같아 간단한 토이 프로젝트를 진행해보았다. 이번 프로젝트의 목표는 react의 기초를 다져보는 것도 있지만 어떤 기술을 사용할 때 왜 해당 기술을 사용하는지를 알고 사용하자!는 것과 가능한한 컴포넌트를 쪼개서 재사용할 수 있게끔 컴포넌트를 분리해보는 것이었다. 아직 더 붙일 살이 많은 프로젝트이지만 차근차근 진행해 나가보려 한다.

used

  • react
  • react-router
  • styled-component
  • axios

프로젝트 구조

구현

promise.all을 통해 동시에 여러 프로미스 실행하기

비동기 통신 작업의 완료를 보장하기 위해 async-await으로 각각 하나의 비동기 작업을 처리한다면, 하나의 비동기 통신이 완료될 때까지 기다린 후에야 다음 비동기 통신이 실행될 수 있다. 이때 만약 비동기로 받아오는 데이터의 수가 많거나 비동기 통신 자체가 많아지면 다음 비동기 작업이 수행되는데 오랜 시간이 걸리게 된다. 따라서 이번 프로젝트에서는 (사실 받아오는 데이터 수 자체는 많지 않아 현재로선 효과는 미미하긴 하다) promise.all 을 통해 비동기 작업들을 동시에 실행시켜 프로미스 결과를 받아오도록 했다.

  • promise.all 방식
async()=>{ 
        const [nowPlayingData, upcomingData] =
            await Promise.all([
                instance.get('/movie/now_playing'),
                instance.get('/movie/upcoming')
            ]);
    
  • async-await 방식
async() =>{
    const res = await instance.get('/movie/now_playing');
    const res2 = await instance.get('/movie/upcoming');
    return [res, res2];
}

아래는 만약 NowPlayingMovie와 UpcomingMovie 비동기 통신을 통해 각각 400개의 데이터를 받아온다고 가정했을 때의 소요시간이다. (효과를 극대화하기 위해 400개라 가정)
(상 async-awiat 방식, 하 promise.all방식)

context API를 통해 전역 영화 state 관리하기

이번 프로젝트에서 api로 받아와 사용한 데이터는 상영 중인 영화정보, 개봉예정 영화정보, 개별 영화의 detail 정보이다. 이중 앞의 2가지 데이터는 대부분의 컴포넌트에서 사용할 전역적인 데이터라 각각 context를 생성하여 provider에 등록해 여러 컴포넌트에서 영화 정보에 접근할 수 있게 했다.

export default function MovieStateProvider({children}){

    const [nowPlaying, setNowPlayingMovie ] = useState({
        data: [], 
        loading : true
    });
    const [upcoming, setUpcomingMovie ] = useState({
        data: [], 
        loading : true
    });
    
    const getData = async()=>{ 
        const [nowPlayingData, upcomingData] =
            await Promise.all([
                NowPlayingMovie(),
                UpcomingMovie()
            ]);
            setNowPlayingMovie((prev) => {
                return {...prev, data: nowPlayingData, loading: false}
            });
            setUpcomingMovie((prev) => {
                return {...prev, data: upcomingData, loading: false}
            });
    }

    useEffect(()=> {   
        if(!nowPlaying.data.length){
            getData();
        }
        else return;
    },[]);

    return (
        <>
        <NowPlayingMovieContext.Provider value={nowPlaying}>
            <UpcomingMovieContext.Provider value={upcoming}>
            {children}
            </UpcomingMovieContext.Provider>
        </NowPlayingMovieContext.Provider>
        </>
    )
}

렌더링 직 후 api통신으로 데이터를 받아오기 위해서 useEffect에서 getData를 호출하였다. 이 후 받아온 데이터는 setState를 해주었고 해당 state들을 provider에 각각 등록함으로써 하위 컴포넌트들이 사용할 수 있게 해주었다.

styled-component로 전역 style 설정 및 동적 스타일링

컴포넌트에서 전역적으로 설정될 style은 styled-component의 GlobalStyle을 통해 지정해주었다. 또한 각각의 영화 item 별로 해당영화의 poster 이미지를 background image로 설정해주기 위해서 image url을 컴포넌트에게 props로 넘겨주었다. 이렇게 속성값을 전달해 styling을 할 수 있다는 점과 별도로 css 파일들을 만들지 않고 작업할 수 있다는 점이 아주 편리했다.

${props => `
            background-image:
            url('${IMAGE_URL+props.url}');`}



<Item url={poster_path}>

그외

  • 데이터 로딩 표시 기능
    초기 state의 loading 상태는 true로 주고, 이 경우에는 loading 컴포넌트를 띄워주었다. api로 데이터를 받아와 setState까지 완료했다면 loading을 false로 바꿔주었다.

  • pagination 기능
    pagination을 통해 한 화면에 영화 정보를 20개씩만 나타내었다.

  • 인기 순서대로 리스트 정렬 및 별점 표시 기능
    api 데이터에서 제공하는 popularity 변수를 이용해, 해당 변수의 값이 큰 순서로 배열을 sort하여 top20의 인기순 영화리스트를 보여주었다.
    api 데이터에서 제공하는 vote_average 변수를 이용하여 css를 통해 영화의 평점을 별점으로 시각화하였다.

배포

https://nahyyun.github.io/react-movie-app/

느낀 점

이번 프로젝트를 통해서 모호하게 알고 있던 비동기 방식을 확실히 이해할 수 있게 되었고 react의 기초부분을 다시 복습하면서 다져볼 수 있는 좋은 기회였다고 생각한다. 또한 컴포넌트를 재사용하거나 관리하기 편리하도록 컴포넌트를 분리해서 사용하는 게 중요하다라는 것을 느꼈다.
작은 규모의 프로젝트여서 state를 관리하고 공유하는게 어렵지는 않았다. 오히려 저번 프로젝트에서는 bootstrap을 사용했기 때문에 styling이 수월했어서 그런지 이번엔 css 작업에서 시간이 좀 많이 소요됐다.
이 프로젝트는 여기서 끝내지 않고 더 빌드업 할 예정이다. 현재 생각하고 있는 기능으로는 개인 사용자화 기능 그리고 페이지네이션 부분을 무한스크롤로도 구현해보고 싶다. 또한 더 많은 데이터를 사용해 이를 효율적으로 관리하기 위해서 redux를 사용할 예정이다. 아직 redux를 배우기 전이지만 context api와 어떻게 어떤 점이 다른지 직접 체감해보고 싶다. 프로젝트의 규모가 더 커지게 된다면 컴포넌트의 렌더링을 최적화시킬 수 있는 방법들도 적용해보고 싶다.

좋은 웹페이지 즐겨찾기