💻오늘 배운 내용
React Router Dom
페이지를 구현할 수 있게 해주는 패키지 (여러 페이지를 가진 웹을 만들 수 있게 된다)
패키지 설치
yarn add react-router-dom
react-router-dom 사용순서
- 페이지 컴포넌트 생성
- Router.js 생성 및 router 설정 코드 작성
- App.js에 import 및 적용
- 페이지 이동 테스트
// Router.js 파일 예시
import React from "react";
// 1. react-router-dom을 사용하기 위해서 아래 API들을 import.
import { BrowserRouter, Route, Routes } from "react-router-dom";
// 2. Router 라는 함수를 만들고 아래와 같이 작성한다.
// BrowserRouter를 Router로 감싸는 이유는,
// SPA의 장점인 브라우저가 깜빡이지 않고 다른 페이지로 이동할 수 있게 만들어준다!
// path는 사용하고싶은 "주소"
// element는 해당 주소로 이동했을 때 보여주고자 하는 컴포넌트
const Router = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="about" element={<About />} />
<Route path="contact" element={<Contact />} />
<Route path="works" element={<Works />} />
</Routes>
</BrowserRouter>
);
};
export default Router;
Hooks
useNavigate
보내고자 하는 path로 페이지를 이동시킬 때 사용하는 hook
navigate 를 생성하고, navigate(’보내고자 하는 url’) 을 통해 페이지를 이동
// src/pages/home.js
import { useNavigate } from "react-router-dom";
const Home = () => {
const navigate = useNavigate();
return (
<button
onClick={() => {
navigate("/works");
}}
>
works로 이동
</button>
);
};
export default Home;
useLocation
현재 위치하고 있는 페이지의 여러가지 정보를 추가적으로 얻을 수 있다.
이 정보들을 이용해서 페이지 안에서 조건부 렌더링에 사용하는 등, 여러가지 용도로 활용 가능하다.
// src/pages/works.js
import { useLocation } from "react-router-dom";
const Works = () => {
const location = useLocation();
console.log("location :>> ", location);
return (
<div>
<div>{`현재 페이지 : ${location.pathname.slice(1)}`}</div>
</div>
);
};
export default Works;
Link
훅이 아니지만, 꼭 알아야 할 API
a 태그의 기능을 대체하는 API
JSX에서 a 태그를 사용해야 한다면, 반드시 Link 를 사용해서 구현해야 한다.
왜냐하면 a 태그를 사용하면 페이지를 이동하면서 브라우저가 새로고침(refresh)되기 때문이다.
import { Link, useLocation } from 'react-router-dom';
const Works = () => {
const location = useLocation();
console.log('location :>> ', location);
return (
<div>
<div>{`현재 페이지 : ${location.pathname.slice(1)}`}</div>
<Link to="/contact">contact 페이지로 이동하기</Link>
</div>
);
};
export default Works;
Dynamic route
동적 라우팅이라고도 말하는데
path에 유동적인 값을 넣어서 특정 페이지로 이동하게끔 구현하는 방법을 말한다.
<Route path="works/:id" element={<Works />} />
path에 works/:id 라고 path가 들어간다. :id 라는 것이 바로 동적인 값을 받겠다라는 의미
:id 는 useParams 훅에서 조회할 수 있는 값이 된다.
useParam
path의 있는 id 값을 조회할 수 있게 해주는 hook
만약에 works/1로 이동하면 1 이라는 값을 주고, works/100으로 이동하면 100 이라는 값을 사용
예시)
// src/pages/Works.js
import React from 'react';
import { Link, useParams } from 'react-router-dom';
const data = [
{ id: 1, todo: '리액트 배우기' },
{ id: 2, todo: '노드 배우기' },
{ id: 3, todo: '자바스크립트 배우기' },
];
function Works() {
return (
<div>
{data.map((work) => {
return (
<div key={work.id}>
<div>할일: {work.id}</div>
<Link to={`/works/${work.id}`}>
<span style={{ cursor: 'pointer' }}>➡️ Go to: {work.todo}</span>
</Link>
</div>
);
})}
</div>
);
}
export default Works;
링크를 통해 이동한 페이지 내에서 param을 통해 id 조회 후 페이지 표시 ▽
// src/pages/Work.js
import React from 'react';
import { useParams } from 'react-router-dom';
const data = [
{ id: 1, todo: '리액트 배우기' },
{ id: 2, todo: '노드 배우기' },
{ id: 3, todo: '자바스크립트 배우기' },
];
function Work() {
const param = useParams();
const work = data.find((work) => work.id === parseInt(param.id));
return <div>{work.todo}</div>;
}
export default Work;
❓발생한 이슈/고민
이전에 만들었던 Todo List에 React Router Dom을 활용하여 상세페이지를 추가로 구현하기
💡해결과정
shaed 폴더 생성 > Router.js 파일 생성 후
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Home from 'pages/Home';
import Detail from 'pages/Detail';
const Router = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/detail/:id" element={<Detail />} />
</Routes>
</BrowserRouter>
);
};
export default Router;
홈과 디테일 페이지의 라우터를 설정해주었다.
import React from 'react';
import Router from './shared/Router';
const App = () => {
return <Router />;
};
export default App;
app.js에서는 라우터 파일로 통하게 하고,
import React from 'react';
import '../App.css';
import styled from 'styled-components';
import Header from 'components/Header';
import Form from 'components/Form';
import List from 'components/List';
import Cappadocia from 'img/Cappadocia.jpg';
function Home() {
return (
<>
<StSection />
<StLayout>
<Header />
<Form />
<List />
</StLayout>
</>
);
}
export default Home;
const StSection = styled.section`
background-image: linear-gradient(
to right,
rgba(185, 98, 239, 0.8),
rgba(114, 166, 250, 0.8)
),
url(${Cappadocia});
background-size: cover;
width: 100%;
height: 300px;
overflow: hidden;
position: relative;
z-index: 0;
`;
const StLayout = styled.div`
max-width: 1200px;
min-width: 800px;
margin: 0 auto;
display: flex;
position: relative;
top: -230px;
background: none;
flex-direction: column;
align-items: center;
`;
home을 메인으로 두고 home에서 컴포넌트들을 뿌려주었다.
<StBtns>
<Link to={`/detail/${item.id}`}>
<StImg src={Detail} alt="상세보기" />
</Link>
<StDeleteBtn onClick={() => onClickDeleteBtn(item.id)}>
<StImg src={Delete} alt="삭제버튼" />
</StDeleteBtn>
</StBtns>
삭제버튼 옆에 상세보기 버튼을 추가하여 상세페이지로 이동하는 링크 API를 달아주었다.
import React from 'react';
import styled from 'styled-components';
import { useSelector } from 'react-redux';
import { useNavigate, useParams } from 'react-router-dom';
function Detail() {
const params = useParams();
const todos = useSelector((state) => state.todos.todos);
const navigate = useNavigate();
const foundTodo = todos.find((item) => {
return item.id == params.id;
});
return (
<StDiv>
<StId>ID : {foundTodo.id}</StId>
<StTitle>{foundTodo.title}</StTitle>
<StP>{foundTodo.contents}</StP>
<StBtn
onClick={() => {
navigate('/');
}}
>
이전으로
</StBtn>
</StDiv>
);
}
export default Detail;
일주일 간.....고생많았다...나야..
🧐궁금점과 부족한 내용
사실 상세페이지는 모달로 페이지 위에 띄우고 싶었는데
검색해보니 '리액트 라우터를 이용해서 간단하게 모달 만들기!' 이런 포스팅들도 많던데
나는 자꾸 오류가 나서 포기했다. 왜 안되는지 모르겠다. 오래 고민해봤지만 해결책을 못 찾아서..
할 일이 많아서 포기하고 넘어가지만 다음에 여유가 되면 다시 도전해보면 좋을 것 같다.
'내일배움캠프 > Today I Learned' 카테고리의 다른 글
[TIL 2023.07.04] Redux Toolkit / 옵셔널 체이닝? (0) | 2023.07.04 |
---|---|
[TIL 2023.07.03] Redux란 무엇인가 (0) | 2023.07.03 |
[TIL 2023.06.22] Redux에 대하여 2 (Action Creator, Payload, useDispatch, Ducks 패턴) (0) | 2023.06.23 |
[TIL 2023.06.21] Redux에 대하여 1 (개념 및 초기셋팅~Module 만들기 및 스토어에 연결) (0) | 2023.06.22 |
[TIL 2023.06.20] React Hooks useContext / useCallback / useMemo (0) | 2023.06.21 |