드디어 리액트 기초강의끝!!
이젠 typescript를 보려고하는데 보는 매일 안쓰다보니 ㅠ 글이 엉망이다.
강의 볼때마다 글 쓰도록 해봐야지...
강의 유튜브 주소 :
https://www.youtube.com/watch?v=V3QsSrldHqI&list=PLcqDmjxt30RtqbStQqk-eYMK8N-1SYIFn
리액트 라우터
라우터를 쓰기위해서 모듈을 설치해준다.
필요한 것은 react-router와 react-router-dom이다.
npm i react-router react-router-dom
react-router는 웹, 앱 모두 사용할 수 있다고 한다.
react-router-dom이 웹브라우저에서 사용하기 위해 필요한것들이 있다고 한다.
react-router만 설치해도 종속성에 의해 react-router-dom이 설치된다고 한다.
staticRouter와 hashRouter, browserRouter가 있다고 한다.
import React from 'react';
import { BrowerRouter, hashRouter, staticRouter } from 'react-touter-dom';
제일많이쓰는건 browserRouter.
import React from 'react';
import { BrowerRouter } from 'react-touter-dom';
const Test () => {
retern (
<BrowserRouter>
//이렇게 감싸줘야한다.
</BrowserRouter>
)
};
혹은 ReactDOM으로 render감싸주는 곳에서 컴포넌트를 감싸줘도 된다고 한다.
// app.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(<BrowerRouter><App/></BrowserRouter, document.querySelector('#root'));
라우터는 페이지로 만들고 싶은 것들의 경로를 임의로 만들어 작업해준다.
가상의 페이지주소이기때문에 사용자가 주소로 접속할 경우 에러가 난다.
import React from 'react';
import { BrowerRouter, Route } from 'react-touter-dom';
import TestChild from './TestChild';
const Test () => {
retern (
<BrowserRouter>
<Route path="./경로" component={TestChild}></Route>
</BrowserRouter>
)
};
가상의 주소로 넘어갈 수 있도록 앵커 태그들이 필요한데, a태그를 사용할 경우에는 에러가 난다.
리액트 라우터는 페이지가 존재하는게 아니라 페이지가 이동하는 것처럼 흉내내는 것이기 때문이다.
따라서 브라우저에서 제공하는 a태그를 사용할 경우 라우터가 인식하지 못한다.
리액트 라우터에서 제공하는 <Link>태그를 사용해준다.
// (X)
retern (
<BrowserRouter>
<a href="주소"></a>
<Route path="./경로" component={TestChild}></Route>
</BrowserRouter>
)
import React from 'react';
import { BrowerRouter, Route, Link } from 'react-touter-dom';
import TestChild from './TestChild';
const Test () => {
retern (
<BrowserRouter>
<Link to="주소">라우터보기</Link>
<Route path="./경로" component={TestChild}></Route>
</BrowserRouter>
)
};
<Link>태그는 페이지의 이동이 아니라 보여지게 흉내내는 것이다.
라우터에게 보여져야할 주소값을 전달한다.
브라우저상에서는 Link가 a태그로 표현된다.
이때 Link태그를 클릭하여 주소를 이동한 후에 새로고침을 하게되면 에러가 발생한다.
또한 주소창에 주소를 입력하고 접근해도 에러가 발생한다.
이것은 주소창으로 접근시에(새로고침도 포함) 서버에 요청이 가기 때문인데, 가상의 주소는 프론트에서만 알고 있기 때문에 서버에서는 에러를 반환한다.
이 부분은 실제 페이지가 여러개가 아니기때문이다.
hashRouter
browserRouter와 거의 비슷하지만 주소사이에 hash값이 들어가게 된다.
[ localhost:8080/#/주소 ] 이런형식으로 보여진다.
import React from 'react';
import { HashRouter, Route, Link } from 'react-touter-dom';
import TestChild from './TestChild';
const Test () => {
retern (
<HashRouter>
<Link to="주소">라우터보기</Link>
<Route path="./경로" component={TestChild}></Route>
</HashRouter>
)
};
hashRouter의 장점은 주소를 이동한 후에 새로고침을 해도 에러가 나지 않고 화면이 나타난다.
이유는 해쉬값(#)때문이다.
browserRouter는 주소가 깔끔한 대신에 새로고침시 서버에 요청이 들어가게되는데 hashRouter는 해쉬값때문에 서버에 요청이 가지않는다. 단점은 서버가 주소의 이동을 모르는 것이다(페이지 존재유무)
이렇게 되면 SEO에 불이익을 받게되고 검색엔진에 접근이 안되게 되면.... 사이트 검색이 안될수도 있다.
이것은 실무에서 엄청난 불이익이다.
따라서 보통 실무에서는 해쉬라우터를 사용안하고 브라우저라우터를 사용한다.
관리자페이지나 SEO에 전혀 상관이없는 사이트같은경우에는 해쉬라우터를 사용하기도 한다.
해쉬라우터는 배포시에 편하다고 한다. 새로고침때 브라우저만 동작하기때문에 어떤 브라우저든 잘 동작한다고 한다.
브라우저 라우터를 쓰면 검색엔진에는 검색이 되나 새로고침이나 주소값 접근의 문제를 해결해야한다.
이것은 서버에 추가적인 세팅으로 해결할 수 있다.
페이지가 존재하는 것을 서버에 알려줘야한다고한다.
서버쪽 세팅시 검색엔진도 신경써야한다.
라우터가 100개가 되고 200개가 되고 방대해질 경우에는 동적 라우터매칭을 사용한다.
:name 값은 파라미터로 동적으로 변경가능하다.
import React from 'react';
import { HashRouter, Route, Link } from 'react-touter-dom';
import GameMatcher from './GameMatcher';
import TestChild from './TestChild';
const Test () => {
retern (
<HashRouter>
<Link to="/game/number">게임1</Link>
<Link to="/game/lottory">게임2</Link>
<Link to="/game/paper">게임3</Link>
<Link to="/game/index">게임 매처</Link>
<Route path="/game/:name" component={GameMatcher}></Route>
</HashRouter>
)
};
동적 라우터를 사용해서 라우터 하나로 여러개를 처리한다.
this.props.history.match는 라우터 to에 담았던 경로값이 포함되어있다.
history, location, match가 undefined가 된다면 라우터 컴포넌트에 cameMatcher를 넣어준다.
라우터랑 연결이 안되어있는 라우터의 경우 withRouter를 사용해서 hoc형식으로 감싸주게되면 사용할 수 있다.
import React, {component} from 'react';
import {withRouter} from 'react-router-dom';
class GameMatcher extends Component{
render(){
return(
<div>
</div>
);
}
}
export default withRouter(GameMatcher);
location, match, history
history에는 앞으로가기, 뒤로가기 등의 페이지 이동에 대한 이력이 남아있다.
제공하는 메서드들이 있어서 go나 go back등 (앞으로가기)의 기능을 제공할 수 있다.
그래서 history를 통해 눈속임으로 페이지의 이동을 구현할 수 있다.
이때 브라우저가 제공하는 기본 메서드를 사용하면 안된다.(라우터는 브라우저 기본기능을 통해 이 기능을 구현하고 있다)
match는 path가 실제 라우트에 등록한 값을 알 수 있다.
:name 파라미터에 실제 어떠한 값이 들어왔는지 알 수 있다.
이 값은 match의 params에 들어가있다.
location은 주소에 대한 정보나 서치, 해쉬값등이 들어있다.
라우터에서 import하던것들을 똑같이 import해준다.
그후에 분기처리한다.
import React, {component} from 'react';
import {withRouter} from 'react-router-dom';
import Number from './number';
import RSP from './RSP';
import Lotto from './Lotto'
class GameMatcher extends Component{
render(){
if(this.props.match.params.name === 'number'){
return <Number />
}else if(this.props.match.params.name === 'RSP'){
return <RSP />
}else if(this.props.match.params.name === 'Lotto'){
return <Lotto />
}else{
return <div>일치하는 게임이 없다</div>;
}
}
}
export default withRouter(GameMatcher);
길어지는것은 어쩔수없다고 하며 어느 부분이던 길어지는 부분이 존재하기 때문에 선택사항이라고 한다.
history.pushAPI를 사용할 경우 주소를 변경할 수 있다.
3번째 인자값으로 주소값을 전달한다.
history.push('', '', '변경할 주소값');
this.props.history와 history.push는 다르며 브라우저의 historyAPI를 사용하면 안된다.
리액트라우터에서 제공하는 것을 사용해야 에러가 나지 않는다.
import React from 'react';
import { HashRouter, Route, Link } from 'react-touter-dom';
import GameMatcher from './GameMatcher';
import TestChild from './TestChild';
const Test () => {
retern (
<HashRouter>
<Link to="/game/number?query=10&data=1">게임1</Link>
<Link to="/game/lottory">게임2</Link>
<Link to="/game/paper">게임3</Link>
<Link to="/game/index">게임 매처</Link>
<Route path="/game/:name" component={GameMatcher}></Route>
</HashRouter>
)
};
to 뒤의 값에 쿼리스트링값을 넘길 수 있는데
?키=값&키=값 형식으로 작성할 수 있으며 &를 통해 연장할 수 있다.
쿼리스트링값은 서버에서도 확인할 수 있다.
이 쿼리스트링은 location의 search에서 확인할 수 있다.
import React, {component} from 'react';
import {withRouter} from 'react-router-dom';
import Number from './number';
import RSP from './RSP';
import Lotto from './Lotto'
class GameMatcher extends Component{
render(){
// slice해서 물음표를 제거한뒤 URLSearchParams에 담아줘야하다.
let urlSearchParams = new URLSearchParams(this.props.location.search.slice(1));
if(this.props.match.params.name === 'number'){
return <Number />
}else if(this.props.match.params.name === 'RSP'){
return <RSP />
}else if(this.props.match.params.name === 'Lotto'){
return <Lotto />
}else{
return <div>일치하는 게임이 없다</div>;
}
}
}
export default withRouter(GameMatcher);
쿼리스트링을 사용하려면 URLSearchParams가 필요하다.
slice해서 물음표를 제거한뒤 URLSeatchParams는 빈객체가 아니며 URLSearchParams에 담아줘야하다.
보통 쿼리스트링은 게시판 작업시에 쓰인다.
해쉬라우터에는 뒤에 #abc=1234 식으로 붙일 수 있는데, 이건 서버는 모르고 브라우저만 안다.
실제적으로 많이 쓰이지 않는다.
서버가 모르면 쿼리스트링을 딱히 쓸때가 별로 없기때문이다.
함수 컴포넌트
props자리에 들어있다. 클래스컴포넌트는 this.props로 접근한다.
다만 라우터에 연결되어있지 않다면 withRouter안에 넣어줘야 사용할 수 있다,
const Games = ({ match, location, history }) => {
// ....
}
export default withRouter(Games);
props를 넘길 수도 있다.
부모컴포넌트의 props를 자식컴포넌트에 넘기는게 목적이라면 render를 쓰는게 좋다.
<Route path="/game/:name" component={() => <GameMatcher props="1234" />} ></Route>
<Route path="/game/:name" render={(props) => <GameMatcher props={props}>} ></Route>
실제로 작업을 하다보면 동적 라우터가 있어도 주소고정라우터가 필요할 경우가 있다.
이때 하나만 렌더링 시키고 싶다면 switch를 사용한다.
<Switch>
<Route path="/game/:name" render={(props) => <GameMatcher {...props} />} ></Route>
<Route path="/game/Number" render={(props) => <GameMatcher {...props}/>} ></Route>
</Switch>
switch안에 있을경우 여러개가 렌더링이 되지 않으며 일치하는 하나만 렌더링이된다.
exact는 정확하게 일치하는 경우에만 렌더링을 시키는 경우인데 switch와 함께 쓸수도 있다.
아래와 같은 경우에 쓰는데 주소가 겹치게되는 경우에 사용된다.
만약 exact가 '/'값에 없다면 '/game/Number/' 접근하게 될 경우 switch로 인해 하나만 렌더링이 되어야하기때문에 '/'로 ㄷ등록된 컴포넌트가 렌더링이되는 현상을 겪을 수 있다.
<Switch>
<Route exact path="/" render={(props) => <GameMatcher {...props} />} ></Route>
<Route path="/game/Number" render={(props) => <GameMatcher {...props}/>} ></Route>
</Switch>