ReactJS로 영화 웹 서비스 만들기
ReactJS로 영화 웹 서비스 만들기
개발환경 세팅
node -v
npm -v
npx -v
git --version
- 위의 명령 실행해서 없으면 설치하기
npx
npm에서 제공하는 패키지 실행 도구로, 패키지를 따로 설치하지 않고 일회성으로 사용할 수 있는 기능을 제공한다. (npm 5.2.0 버전 이상이면 같이 설치됨)
리액트 프로젝트 생성
- create-react-app으로 리액트 프로젝트 생성
npx create-react-app [폴더명]
왜 나는 파일이 제대로 안 만들어질까....
❗ create-react-app
만 쳐서 전역으로 설치되어 있는지 확인하고, 만약 설치되어 있으면 npm uninstall -g create-react-app
으로 삭제한 후 다시 시도!
깃 연결하기
- 깃 레포 생성 후에 프로젝트에 add
git remote add origin [주소]
- 그리고 commit & push
.gitignore 파일이 세팅되어 있기 때문에 node_modules 폴더 등은 안 올라감!
Virtual DOM
참고
브라우저가 HTML을 전달받으면 DOM 노드 트리를 만드는데, DOM을 조작할 때마다 이 트리가 다시 생성되어 느려진다.
그런데 Virtual DOM은 실제 DOM에 적용하기 전에 가상 DOM에 먼저 조작을 한 다음 결과만을 반영하여 연산을 줄이고 성능을 개선시킨다.
- 리액트가 항상 빠른 것은 아니며, 리액트는 유지보수를 용이하게 해주고 웬만한 경우에 !충분히! 빠르다는 게 장점이라고 한다.
props 유효성 검사
- prop-types 설치
npm i prop-types
(i
는 install
)
- import
import PropTypes from 'prop-types';
- 사용
// 컴포넌트.propTypes = {};
Food.propTypes = {
name: PropTypes.string.isRequired,
picture: PropTypes.string.isRequired,
rating: PropTypes.number,
};
👉 결과는 문제없이 나와도 콘솔에서 오류를 출력해준다.
setState()
에 정확한 값 전달하기
node -v
npm -v
npx -v
git --version
npx
npm에서 제공하는 패키지 실행 도구로, 패키지를 따로 설치하지 않고 일회성으로 사용할 수 있는 기능을 제공한다. (npm 5.2.0 버전 이상이면 같이 설치됨)
npx create-react-app [폴더명]
왜 나는 파일이 제대로 안 만들어질까....
❗
create-react-app
만 쳐서 전역으로 설치되어 있는지 확인하고, 만약 설치되어 있으면npm uninstall -g create-react-app
으로 삭제한 후 다시 시도!
git remote add origin [주소]
.gitignore 파일이 세팅되어 있기 때문에 node_modules 폴더 등은 안 올라감!
Virtual DOM
참고
브라우저가 HTML을 전달받으면 DOM 노드 트리를 만드는데, DOM을 조작할 때마다 이 트리가 다시 생성되어 느려진다.
그런데 Virtual DOM은 실제 DOM에 적용하기 전에 가상 DOM에 먼저 조작을 한 다음 결과만을 반영하여 연산을 줄이고 성능을 개선시킨다.
- 리액트가 항상 빠른 것은 아니며, 리액트는 유지보수를 용이하게 해주고 웬만한 경우에 !충분히! 빠르다는 게 장점이라고 한다.
npm i prop-types
(i
는 install
)import PropTypes from 'prop-types';
// 컴포넌트.propTypes = {};
Food.propTypes = {
name: PropTypes.string.isRequired,
picture: PropTypes.string.isRequired,
rating: PropTypes.number,
};
👉 결과는 문제없이 나와도 콘솔에서 오류를 출력해준다.
setState()
에 정확한 값 전달하기setState()
호출은 비동기적이다.- 호출 직후
this.state
에 새로운 값이 반영되는 것이 아니다.
👉this.state
나this.props
는 렌더링된(화면에 보이는) 값이기 때문! - 객체가 아니라 함수를 전달하면 이전 state 값에 접근할 수 있고,
setState()
호출은 일괄적으로 처리되기 때문에 충돌 없이 값을 반영할 수 있다.
❌
add = () => {
this.setState({ count: this.state.count + 1 });
};
⭕
add = () => {
this.setState((current) => ({ count: current.count + 1 }));
};
컴포넌트 라이프사이클
Mounting
컴포넌트 탄생
constructor()
: 컴포넌트가 생성될 때 제일 먼저 실행render()
: 그 다음 실행componentDidMount()
: 컴포넌트가 처음 render 되었을 때 실행
Updating
업데이트
render()
:setState()
호출 후 실행componentDidUpdate()
: 업데이트 render 이후 실행
Unmounting
컴포넌트 죽음 (페이지 넘길 때, 컴포넌트 교체될 때 ...)
componentWillUnmount()
: 컴포넌트가 사라지기 전에 실행
비동기 요청 처리
async & awiat
기존에 콜백 함수로 처리하던 것을 비동기 함수로 만들어서 보기 좋은 코드로 만든다.
- 함수 앞에
async
키워드를 붙이고 비동기 요청 앞에await
키워드를 붙인다.
getMovies = async () => {
const movies = await axios.get('https://yts-proxy.now.sh/list_movies.json');
};
componentDidMount() {
this.getMovies();
}
👉
getMovies()
가 비동기 함수라고 명시했기 때문에 이 요청이 처리될 때까지 기다린다.
getMovies = async () => { const movies = await axios.get('https://yts-proxy.now.sh/list_movies.json'); console.log(movies.data.data.movies); };
위의 코드를 ES6 문법으로 바꾸면 아래와 같다.
getMovies = async () => { const { data: { data: { movies }, }, } = await axios.get('https://yts-proxy.now.sh/list_movies.json'); console.log(movies); };
문자열(배열) 자르기
// 처음 인덱스부터 마지막 인덱스 전까지 자른 복사본을 리턴한다. (원본 수정 x)
slice(처음 인덱스, 마지막 인덱스)
<p className="movie__summary">{summary.slice(0, 180)}...</p>
깃헙 페이지 배포
- gh-pages 설치
npm i gh-pages
package.json
homepage
추가
"homepage": "https://[사용자명].github.io/[프로젝트명]"
scripts
에deploy
,predeploy
추가- 프로젝트를
build
하면 build 폴더가 생성됨
- 프로젝트를
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"deploy": "gh-pages -d build",
"predeploy": "npm run build" // deploy 명령을 하면 자동으로 실행됨
},
npm run deploy
로 배포
라우터
- react-router-dom 설치
npm install react-router-dom
// App.js
import React from 'react';
// react-router-dom import
import { HashRouter, Route } from 'react-router-dom';
import Home from './routes/Home';
import About from './routes/About';
function App() {
return (
<HashRouter>
<Route path="/" exact={true} component={Home} />
<Route path="/about" component={About} />
</HashRouter>
);
}
export default App;
- Route는 해당 패스에 일치하는 모든 컴포넌트를 렌더링
/about
패스에/
패스가 포함되므로/about
으로 접속하면Home
과About
이 모두 렌더링됨
👉exact={true}
props를 주면 정확히 일치하는 주소일 때만 렌더링!
Link
- 일반
a
태그를 사용하면 웹페이지가 새로고침되기 때문에 라우터가 제대로 동작하지 않는다.
👉 react-router-dom의Link
를 사용해야 함!
// components/Navigation.js
import React from 'react';
import { Link } from 'react-router-dom';
function Navigation() {
return (
<div>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</div>
);
}
export default Navigation;
// App.js
import React from 'react';
// BrowserRouter를 쓰면 주소 끝에 #(Hash)가 안 붙는 대신 깃헙 페이지에 배포가 까다로움
import { HashRouter, Route } from 'react-router-dom';
import Home from './routes/Home';
import About from './routes/About';
import Navigation from './components/Navigation';
function App() {
return (
<HashRouter>
<Navigation />
<Route path="/" exact={true} component={Home} />
<Route path="/about" component={About} />
</HashRouter>
);
}
export default App;
- 꼭 모든 컴포넌트가 라우터 안에 있어야 하는 건 아니지만 Link를 쓰려면 라우터 안에 있어야 함
<Link
to={{
pathname: '/about',
state: {
fromNavigation: true,
},
}}
>
이런 식으로
to
에 오브젝트를 전달하면 해당 컴포넌트에 props로 전달된다.
이렇게
:id
처럼 주소에 변수를 줄 수도 있다.<Route path="/movie/:id" component={Detail} /> // 사용하는 곳에서 `pathname`에 변수 전달 <Link to={{pathname: `/movie/${id}`, ...}}>...</Link>
리다이렉팅
- 요소를 클릭하지 않고 직접 url에 접속하면
props.state
값이 전달되지 않기 때문에 홈으로 리다이렉트를 해준다.
componentDidMount() {
const { location, history } = this.props;
if (location.state === undefined) {
history.push('/');
}
}
- 상세 페이지에서 다시 주소를 호출하면
props.state
값이 전달되지 않기 때문에null
을 리턴하여 렌더링이 되지 않도록 한다.
render() {
const { location } = this.props;
if (location.state) {
return <span>{location.state.title}</span>;
} else {
return null;
}
}
❓
근데 어떻게 홈으로 리다이렉트 되는지는 잘 모르겠음...
Author And Source
이 문제에 관하여(ReactJS로 영화 웹 서비스 만들기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@chez_bono/ReactJS로-영화-웹-서비스-만들기저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)