React
20210607 React04 : Routing(path, id, queryString 방식) URLSearchParams, query-string 패키지, Switch-NotFound, JSX링크로 라우팅 이동(RRD : Link, NavLink), JS로 라우팅 이동(RRD: history, withRouter, Redirect)
React 04
Dynamic Routing
- URL을 동적으로 입력하는 방법
Path에 id값 사용 방식
- Router에서 Route에 연결한 라우트 Component의 경우 path에
:이름
을 붙여서 url을 표현 하게 되면 해당 Component 함수에서 받아오는 인자 (props)의 경우 객체이다. - 그 객체는 해당 객체의 match에 params 안에 path로 지정한 이름으로 key를 가지는 key-value의 구조로 가지게 됨
- 자동으로 params 객체에
이름: '1'
의 item을 가지게 됨 :
를 사용하는 경우 필수 요소라서/profile/:id
의 표현인 경우/profile
를 포함한다고 인식하고, 이처럼 따로 라우트 처리를 해줘야 함
// id라는 이름으로 path를 붙인 경우 -> 라우트 처리
import { BrowserRouter, Route } from "react-router-dom";
import "./App.css";
import About from "./pages/About";
import Home from "./pages/Home";
import Profile from "./pages/Profile";
function App() {
return (
<BrowserRouter>
<Route path="/" exact component={Home} />
<Route path="/profile" exact component={Profile} />
<Route path="/profile/:id" component={Profile} />
<Route path="/about" component={About} />
</BrowserRouter>
);
}
export default App;
export default function Profile(props) {
console.log(props);
const id = props.match.params.id;
console.log(id, typeof id);
// 1, string
return (
<div>
<h2>Profile 페이지 입니다.</h2>
{id && <p>id 는 {id} 입니다.</p>}
</div>
);
}
Path에 QueryString을 사용 방식
?이름=값
으로 url 표현 부분- 이것을 Query String이라고 함
- 필수가 아니고 옵션이라 라우트 처리가 필요 없음(즉, path에 표시해서 지정해줄 필요가 없음)
- 해당 url 표현 부분의 경우 Route에 연결한 컴포넌트 함수가 받는 인자 객체 안 location에 search에 string으로 들어가 있음
- search가 담고 있는 내용이 string이라서 직접적으로 사용하려면 이름, 값 부분을 가져올수 있게 가공을 해야하는데 방법이 2가지가 있음
- 브라우저의 내장 객체인 URLSearchParams를 활용함
URLSearchPrams
URLSearchParams
객체를 분석할search
를 넣어 주면서new
키워드로 생성하여 사용하고 해당 객체를 받아서 console에 찍어보면 별다른 데이터가 바로 보이진 않고, 해당 객체에서 지원하는 method를 활용해야 한다.get()
method를 통해서 가지고 오고 싶은 search부분의 이름 부분을 인자로 넣어 값을 가져 올 수 있음- 단점
- 브라우저의 내장 전역 객체이기 때문에 브라우저에 따라 지원 유무가 다르다.
- key를 무조건 제공해야 꺼내 쓸수 있다.
// 기본적으로 URLSearchParams를 제공하기 때문에 import 필요 없음
export default function About(props) {
console.log(props);
const searchParams = props.location.search;
const obj = new URLSearchParams(searchParams);
console.log(obj); // {}
console.log(obj.get("name")); // kim
return <div>About 페이지 입니다.</div>;
}
query-string 패키지
- 설치 :
npm i query-string
- URLSearchParams의 단점을 극복시켜 줌
- queryString을 key-value 객체 형태로 만들어줌
- parse 함수를 사용함
// 외부 패키지 이기 때문에 import 필요
import queryString from "query-string";
export default function About(props) {
console.log(props);
const searchParams = props.location.search;
const query = queryString.parse(searchParams);
console.log(query); // {name: "kim"}
return (
<div>
<h2>About 페이지 입니다.</h2>
{query.name && <p>name은 {query.name} 입니다.</p>}
</div>
);
}
Switch로 NotFound 구현하기
Switch
- React-Router-Dom에 있는 컴포넌트 임
- 여러 Route 중 순서대로 먼저 맞는 하나만 보여줌
- exact를 뺄 수 있는 로직을 만들 수 있음 (순서대로 실행되기 때문에 가장 넓은 범위를 제일 나중에 작성하면 됨)
/
path의 경우에는 무조건 exact를 넣어주어야 함(모든 경로에 포함이 되어 있기 때문에)
- 가장 마지막에 어디 path에도 맞지 않으면 보여지는 컴보넌트를 설정해서, Not Found 페이지를 만들 수 있음
// App.js
// Switch 컴포넌트 import
import { BrowserRouter, Route, Switch } from "react-router-dom";
import "./App.css";
import About from "./pages/About";
import Home from "./pages/Home";
import NotFound from "./pages/NotFound";
import Profile from "./pages/Profile";
function App() {
return (
<BrowserRouter>
<Switch>
<Route path="/profile/:id" component={Profile} />
<Route path="/profile" component={Profile} />
<Route path="/about" component={About} />
<Route path="/" exact component={Home} />
<Route component={NotFound} />
</Switch>
</BrowserRouter>
);
}
export default App;
// NotFound.jsx
export default function NotFound() {
return <div>페이지를 찾을 수 없습니다.</div>;
}
JSX링크로 라우팅 이동하기
- 앱 내부에서 페이지 이동하는 것
a 태그 사용 방식 (기존 HTML을 통한 이동 방식)
- 기존 html 이동방식은 a 태그를 사용
- 이미 다운로드된 파일을 이용해서 페이지를 이동하는 것이 아닌, 일반적인 사이트 처럼 주소 url의 page를 찾는 기능을 수행함으로서 새롭게 앱을 다시 다운받아 새로고침하게 됨
function App() {
return (
<BrowserRouter>
<a href="/">Home</a>
<Switch>
<Route path="/profile/:id" component={Profile} />
<Route path="/profile" component={Profile} />
<Route path="/about" component={About} />
<Route path="/" exact component={Home} />
<Route component={NotFound} />
</Switch>
</BrowserRouter>
);
}
Link Component (링크 컴포넌트 - react-router-dom)
- 내부의 앱이 가진 페이지에서 맞는 페이지를 이동하여 출력 함
- Link 컴포넌트는 react-router-dom 에서 제공함
- 사실 출력하여 dev tool로 보면 a태그로 되어 있음 (단, 실제로 서버에서 페이지를 가져와서 이동하는게 아닌, 앱 내에서 페이지를 찾아 도와줌)
- 참고) 주소창으로 path를 찍으면 새로고침 됨
function App() {
return (
<BrowserRouter>
<Links />
<Switch>
<Route path="/profile/:id" component={Profile} />
<Route path="/profile" component={Profile} />
<Route path="/about" component={About} />
<Route path="/" exact component={Home} />
<Route component={NotFound} />
</Switch>
</BrowserRouter>
);
}
- Link 컴포넌트에서는 a 태그의 href와 달리
to
라는 속성 키워드로 사용됨
// src-> components-> Links.jsx
import { Link } from "react-router-dom";
export default function Links() {
return (
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/profile">Proflie</Link>
</li>
<li>
<Link to="/profile/1">Profile/1</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/about?name=kim">About?name=kim</Link>
</li>
</ul>
);
}
NavLink를 사용하는 방식
- react-router-dom에서 제공하는 컴포넌트임
- Link 컴포넌트와 달리, activeClassName, activeStyle처럼 active 상태에 대한 스타일 지정이 가능함
- 현재 주소에 대한 match 상태를 client적으로 표현하는데 유용함
- 현재 브라우저 url 상태와 지정한 경로가 맞으면 여러 스타일링을 표시함
- 브라우저 url과 현재 지정한 경로가 맞는지를 체크하는 matching 알고리즘이고 Route의 path처럼 동작하기 때문에 exact가 있음
- 주의) queryString도 포함관계로 인식해서 따로 구분할 수 있는 로직이 필요함
- NavLink의
isActive
속성을 이용하는데, isActive의 경우 true, false 값중에 true를 받아야 해당 activeStyle이 나타남 - isActive 로 callback을 넣으면,
match
와location
이라는 두개의 인자를 받아 사용할 수 있음 location
의 경우 search에 queryString이 달리기 때문에 search 값이 지정한 값인지를 체크하여 true, false를 return하여 isActive에 할당하면 queryString도 구분이 된다.- (하지만, queryString만 체크하기 때문에 원래 path도 체크해주어야 한다.)
- 원래 path도 체크하기 위해서,
match
인자를 사용함 match
의 경우 브라우저의 url과 해당 link에서 지정한 to가 일치하는지를 확인하여 일치하면 일치한다는 정보를 담은 객체를 return 함, 일치하지 않으면null
을 내보냄
- NavLink의
import { NavLink } from "react-router-dom";
// active시 지정할 스타일링 변수
const activeStyle = { color: "green" };
// activeStyle -> 스타일링 연결
// isActive -> Active에 대한 로직
// match -> path 조건
// location -> qeuryStrig 조건
export default function Links() {
return (
<ul>
<li>
<NavLink to="/" exact activeStyle={activeStyle}>
Home
</NavLink>
</li>
<li>
<NavLink to="/profile" exact activeStyle={activeStyle}>
Proflie
</NavLink>
</li>
<li>
<NavLink to="/profile/1" activeStyle={activeStyle}>
Profile/1
</NavLink>
</li>
<li>
<NavLink
to="/about"
activeStyle={activeStyle}
isActive={(match, location) => {
return match !== null && location.search === "";
}}
>
About
</NavLink>
</li>
<li>
<NavLink
to="/about?name=kim"
activeStyle={activeStyle}
isActive={(match, location) => {
return match !== null && location.search === "?name=kim";
}}
>
About?name=kim
</NavLink>
</li>
</ul>
);
}
JS로 라우팅 이동하기
- react-route-dom에서 제공하는 함수를 이용한 방법
- Route에서 페이지 요청시 받아오는 인자로 props를 받아오는데, 해당 props는 객체로 history, location, match 등의 정보를 가지고 있는데 history 객체를 이용하여 페이지 이동을 할 수 있음
- history에 push 메서드를 활용하여, 안에 경로를 넣으면 해당 페이지로 이동하게 됨
// Login page route
// 로그인 하기 버튼을 누르고 1초뒤 home 페이지로 이동함
export default function Login(props) {
console.log(props); // history, location, match 등이 들어옴
function login() {
setTimeout(() => {
props.history.push("/"); // history 객체에서 제공하는 메서드들을 활용해서 페이지 이동이 가능함(새로고침 없는 페이지)
}, 1000);
}
return (
<div>
<h2>Login 페이지 입니다.</h2>
<button onClick={login}>로그인하기</button>
</div>
);
}
따로 기능을 분리하여 component로 관리하는 경우
- porps에 대한 기능을 사용하려면 page가 바뀔때 받았던 props를 하위 component에 계속 전달 시켜야 함
- 이러한 경우 나중에 복잡해 지면 문제가 생김
// login page
import LoginButton from "../components/LoginButton";
export default function Login(props) {
return (
<div>
<h2>Login 페이지 입니다.</h2>
<LoginButton {...props} />
</div>
);
}
// logtin button component
export default function LoginButton(props) {
function Login() {
setTimeout(() => {
props.history.push("/");
}, 1000);
}
return <button onClick={Login}>로그인 하기</button>;
}
해결방법 : HOC (Higher Order Component)의 withRouter 함수
- react-router-dom에서 제공하는 HOC인
withRouter
메서드를 사용- 기존 상위 page component에서 하위componet로 props를 뿌리지 않고, 해당 기능을 사용할 component에서 withRouter 메서드로 해당 출력 component function을 한번 묶어서 export 처리 하면 됨
- 즉, props를 활용하는 component에게 Router에서 props를 계속 전달할 필요 없이 바로 props를 받는것 처럼 사용이 가능함
import { withRouter } from "react-router-dom";
export default withRouter(function LoginButton(props) {
function Login() {
setTimeout(() => {
props.history.push("/");
}, 1000);
}
return <button onClick={Login}>로그인 하기</button>;
});
Redirect Component
- react-router-dom에서 지원함
- JSX 형태로 사용
- Redirect 컴포넌트는 render가 되면 지정한 경로로 이동하게 됨
- Route component에서는 render 속성을 지원함 isLogin 변수에 따라서 홈으로 갈지, Login component를 보여줄지 정할 수 있음
const isLogin = false;
function App() {
return (
<BrowserRouter>
<Links />
<NavLinks />
<Switch>
<Route
path="/login"
render={() => (isLogin ? <Redirect to="/" /> : <Login />)}
/>
<Route path="/profile/:id" component={Profile} />
<Route path="/profile" component={Profile} />
<Route path="/about" component={About} />
<Route path="/" exact component={Home} />
<Route component={NotFound} />
</Switch>
</BrowserRouter>
);
}
export default App;