웹개발 (4)

ppparkta·2022년 11월 10일
1

웹개발

목록 보기
5/26

오늘 학습한 내용

  • async, await
  • react router
  • 동적 url (useParams)

실습 movie app

영화 정보가 담긴 api를 활용해 간단한 영화 소개 사이트를 만들고 있다.

async, await

어제 fetch 후 then을 쓰는 이유에 대해 나름 찾아봤는데 요즘은 then보다는 async-await을 많이 사용한다고 한다. 자바스크립트 튜토리얼에 이와 관련해 자세히 설명돼있다.

내가 바로 이해하기엔 앞서 건너뛴 내용들이 많아서 이 문서의 상위 문서를 먼저 공부하고 뒷 내용을 이해하면 좋을 것 같다.

이게 then을 사용해서 api를 호출하는 코드

useEffect(() => {
	fetch(`https://yts.mx/api/v2/list_movies.json?minimum_rating=8.8&sort_by=year`)
  	.then((response) => response.json())
  	.then((json) => {
        setMoives(json.data.movies);
        setLoading(false);
	});
}, []);

이건 async-await을 사용해서 api를 호출하는 코드

const getMovies = async () => {
  const response = await fetch(
      `https://yts.mx/api/v2/list_movies.json?minimum_rating=8.8&sort_by=year`
    );
  const json = await response.json();
  setMovies(json.data.movies);
  setLoading(false);
}
useEffect(()=>{
	getMovies();
}, [])

아직도 구체적인 동작 원리는 모르겠다. 이 부분은 실습 끝나고 다음주부터 이론 공부하며 채워나가자.

propTypes

위에서 받아온 api를 출력하기 위해 별도의 Movie 컴포넌트를 만들었다.

	<div>
      <img src={coverImage} alt={title} />
      <h2>{title}</h2>
      <p>{summary}</p>
      <ul>{genres === null ? "" : genres.map((g) => <li key={g}>{g}</li>)}</ul>
    </div>

App컴포넌트에서 movie에 대한 정보를 prop로 받아와야 정상적으로 실행한다. 이 때 오류를 줄이기 위해서 propTypes를 지정했다.

Movie.propTypes = {
  coverImage: PropTypes.string.isRequired,
  title: PropTypes.string.isRequired,
  summary: PropTypes.string.isRequired,
  genres: PropTypes.arrayOf(PropTypes.string),
};

React Router

네트워크 계층에서 사용하는 router가 맞다. velog url에서 url의 규칙을 간단히 생각해보면 메인 url은 https://velog.io/이다. 그런데 지금 글을 쓰고 있는 내 하위 페이지는 https://velog.io/write?id=422f7f1e-0cf5-44c1-816c-50de776b5660 라는 복잡한 주소를 갖고 있다.

기본으로 설정된 https://velog.io을 제외하고 보면 "/", "/~~" 이런 주소로 설정된 것을 알 수 있다.

정리하면 유저의 현재 url에 따라서 보여지는 화면을 달리 하고 싶을 때 라우터를 사용한다.

movie 앱에서 영화제목을 클릭하면 세부 페이지로 이동시키고 싶은데, 그때 라우터를 사용해야 한다고 한다.

$ npm i react-router-dom

작업하는 경로에서 명령어를 입력하면 리액트 라우터가 설치된다. src폴더에 routescomponents 폴더를 만들면 준비가 대충 끝난다.

여태까지 App.js에 직접 파일을 작성하는 식으로 프로젝트를 진행했는데, 이제 routes폴더 안의 js파일들이 각 화면을 담당하는 일종의 페이지 역할을 하게 된다.

App.js는 routes폴더를 render한다. App.js파일은 return null; 하고 비워두면 됨.

각각의 컴포넌트 조각들은 components폴더에 넣고 그 컴포넌트를 이용해 만들어진 페이지를 routes폴더에 넣으면 된다.

내가 작업한 프로젝트는 이런 경로로 구성함

기본적으로 Home.js에 있는 페이지가 보여지고, 나중에 url이 /~~~ 등으로 추가되면 Detail.js 페이지를 보여줄 거다.

이제 그런식으로 작업해야한다.

import {
  BrowserRouter as Router, 
  Switch, 
  Route 
} from "react-router-dom";

App.jsreact-router-dom 으로부터 라우터, 스위치, 라우트를 import한다.

function App() {
  return (
    <Router>
      <Switch>
        <Route path="/movie">
          <Detail />
        </Route>
        <Route path="/">
          <Home />
        </Route>
      </Switch>
    </Router>
  );
}

Route 안에 내가 보여주고자 하는 페이지 컴포넌트를 넣는다. path는 홈디렉토리는 "/", 그 외에는 내가 지정해준다.

단, 내가 사용한 react router는 5.3.0버전인데 현재는 업데이트로 인해 Switch가 사라지고 몇가지 변경 사항이 있다고 한다.

🙄 변경사항
1. Switch컴포넌트가 Routes컴포넌트로 대체되었습니다. Switch -> Routes
2. Route컴포넌트 사이에 자식 컴포넌트를 넣지 않고, element prop에 자식 컴포넌트를 할당하도록 바뀌었습니다.

Route path="/" element={< Home / >}

위에서 import하지 않은게 하나 있는데 Link다. (다른 컴포넌트에 넣어야 함) 이런식으로 각 페이지마다 url을 지정해주고, a태그를 통해 이동하게 되면 기능은 정상적으로 작동하지만 리렌더링이 발생한다.

이 문제를 해결하기 위해 Link태그가 존재한다.

Movie컴포넌트에서

import { Link } from "react-router-dom";
<h2><Link to="/movie">{title}</Link></h2>

타이틀 부분만 다음과 같이 수정했다. 리액트 라우터로 "/movie" url을 Detail 컴포넌트로 설정했기 때문에 h2태그를 클릭하면 Detail 페이지로 넘어간다.

동적 url

이런식으로 Link로 이동해버리면 prop를 못 받아오는데 다행히 url에도 변수를 넣을 수 있다고 한다. (dynamic url)

git pages

리액트 내부에서 깃 페이지에 배포할 수 있다고 한다.
package.json의 가장 하단에서 (블럭 내부 아님)

"homepage": "https://ppparkta/github.io/cinema"

를 붙여넣고 디버그 블럭 안에

	"deploy": "gh-pages -d build",
    "predeploy": "npm run build"

를 붙여넣어준다. 이렇게 명령어를 만들면 deploy를 실행할 때 predeploy에서 먼저 파일을 빌드시킨 뒤에 가장 하단에 적어준 homepage주소로 업로드 하겠다는 의미이다.

작업 끝났으면 터미널에

$ npm run deploy

입력해주면 내가 입력한 주소로 업로드된다. 참고로 주소는 https://깃허브아이디.github.io/저장소명 으로 설정해야 한다.

오늘 리액트 기초 강의도 마무리됐지만 저장소 관리를 잘못해서 배포를 하진 못했다. 새로운 저장소를 만들어야 pages에 업로드할 수 있을 것 같다.

내일 할 것

  • async-await 문서 읽고 이해하기
  • 동적 url 활용한 미니 프로젝트 만들기
  • 오늘 만들었던 파일을 스스로 만들기
  • 깃허브 페이지에 배포하기
profile
겉촉속촉

0개의 댓글