1. 리액트 라우터 : 셋팅이랑 기본 라우팅
- 나누고 싶으면 일반 html css js 사이트는 그냥 html 파일 여러개 만들면 그게 하나의 페이지인데
- 근데 리액트는 SPA(single page aplication)로 html 파일을 하나만 사용합니다.
- 그래서 React Router는1개의 html에서 새로고침 없이 필요한 부분을 렌더링 시켜 주소에 맞춰 필요한 화면을 보여줍니다.
- (참고) Routing 라우팅은 기본적으로 네트워크에서 경로를 선택하는 프로세스를 의미한다.
1) react-router-dom 설치하려면
터미널 열어서 아래의 코드를 입력하여 설치합니다.
npm install react-router-dom@6
셋팅은 index.js 파일로 가서
import { BrowserRouter } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
▲ import { BrowserRouter } from "react-router-dom"; 를 해오고
<BrowserRouter> 이걸로 <App/> 이걸 감싸면 끝입니다.
2) 라우터로 페이지 나누는 법
다른 웹사이트를 잘 살펴보면
naver.com/어쩌구로 접속하면 A페이지를 보여주고
naver.com/저쩌구로 접속하면 B페이지를 보여줍니다.
이런 식으로 url 경로마다 다른 페이지를 보여주고 싶으면 이렇게 작성합니다.
(App.js)
import { Routes, Route, Link } from 'react-router-dom'
function App(){
return (
(생략)
<Routes>
<Route path="/detail" element={ <div>상세페이지</div> } />
<Route path="/about" element={ <div>어바웃페이지</div> } />
</Routes>
)
}
1. 우선 상단에서 여러가지 컴포넌트를 import 해오고
2. <Routes> 만들고 그 안에 <Route>를 작성합니다.
3. <Route path="/url경로" element={ <보여줄html> } /> 이렇게 작성하면 됩니다.
<Route path="/" element={ <div>메인페이지에서 보여줄거</div> } />
▲ 이 url 경로는 메인페이지입니다.
3) 페이지 이동 버튼은
링크를 만들고 싶으면 react-router-dom에서 Link 컴포넌트 import 해오고 원하는 곳에서 <Link> 쓰면 됩니다.
<Link to="/">홈</Link>
<Link to="/detail">상세페이지</Link>
이러면 각각 url 경로로 이동하는 링크를 생성할 수 있습니다
2. 리액트 라우터 : navigate, nested routes, outlet
리액트 프로젝트 폴더구조는 비슷한 .js 파일끼리 한 폴더에 묶어놓으면 그냥 그게 좋은 폴더구조입니다.
- 컴포넌트 역할하는 js 파일은 components 폴더에 묶고
- 페이지 역할하는 js 파일은 routes 아니면 pages 폴더에 묶고
- 자주 쓰는 함수가 들어있는 js 파일은 utils 폴더에 묶고
알아서 필요할 때마다 폴더 만들어 모듈화 하면 좋습니다.
import { Routes, Route, Link, useNavigate, Outlet } from 'react-router-dom'
우선 상단에서 이런 것들을 import 해옵니다.
페이지 이동은 Link 써도 된다고 했는데 그게 싫으면 useNavigate() 를 사용해도 됩니다.
function App(){
let navigate = useNavigate()
return (
(생략)
<button onClick={()=>{ navigate('/detail') }}>이동버튼</button>
)
}
useNavigate() 쓰면 페이지 이동시켜주는 함수를 남겨줍니다.
그럼 이제 navigate('/detail') 이런 코드가 실행되면 /detail 페이지로 이동가능합니다.
navigate(2) 숫자넣으면 앞으로가기, 뒤로가기 기능개발도 가능합니다.
- -1 넣으면 뒤로 1번 가기
- 2 넣으면 앞으로 2번 가기 기능입니다.
<🔍LINK와 useNavigate() 의 차이점>
Link는 클릭시 페이지를 바로 이동하게 하는 기능을 하고 useNavigate는 조건을 만족했을때 페이지 전환을 합니다.
- Link의 예시 : 상품을 클릭하면 해당 상품에 대한 디테일페이지로 이동
- useNavigate의 예시 : 회원가입이 완료 되면 메인페이지로 이동
2) 404페이지는
유저가 이상한 경로로 접속했을 때 "없는 페이지입니다" 이런거 보여주고 싶으면
<Route path="*" element={ <div>없는페이지임</div> } />
<Route path="*"> 하나 맨 밑에 만들어두면 됩니다.
* 경로는 모든 경로를 뜻해서
위에 만들어둔 /detail 이런게 아닌 이상한 페이지 접속시 * 경로로 안내해줍니다.
3) 서브경로 만들 수 있는 nested routes
/about/member로 접속하면 회사멤버 소개하는 페이지
/about/location으로 접속하면 회사위치 소개하는 페이지를 만들고 싶으면 어떻게 합니까.
<Route path="/about/member" element={ <div>멤버들</div> } />
<Route path="/about/location" element={ <div>회사위치</div> } />
이렇게 만들어도 되겠지만
<Route path="/about" element={ <About/> } >
<Route path="member" element={ <div>멤버들</div> } />
<Route path="location" element={ <div>회사위치</div> } />
</Route>
이렇게 만들어도 됩니다.
<Route>안에 <Route>를 넣을 수 있는데 이걸 Nested routes 라고 부릅니다.
저렇게 쓰면 /about/member로 접속시 <About> &<div>멤버들</div> 을 보여줍니다.
/about/location으로 접속시 <About> & <div>회사위치</div> 을 보여줍니다.
하지만 저렇게만 짜면 Nested 한 router 의 <div>는 안보이는데요
실은 위처럼 코드짜면 /about/member로 접속시 <About>안에 <div>멤버들</div> 을 보여줍니다.
그래서 <About> 컴포넌트 안에 <div>를 어디다 보여줄지 표기해야 잘보여줍니다.
<Route path="/about" element={ <About/> } >
<Route path="member" element={ <div>멤버들</div> } />
<Route path="location" element={ <div>회사위치</div> } />
</Route>
function About(){
return (
<div>
<h4>about페이지임</h4>
<Outlet></Outlet>
</div>
)
}
위에서 import해온 <Outlet>은 nested routes안의 element들을 어디에 보여줄지 표기하는 곳입니다.
그래서 이렇게 해두면 /about/member로 접속시 <Outlet>자리에 아까의 <div> 박스들이 잘 보입니다.
3. 리액트 라우터 : URL 파라미터로 상세페이지 여러개 만들기
만약에 Detail 이라는 페이지를 만들고 또 그에 따른 상세페이지들( Detail/0, Detail/1 Detail/2 .. )을 만든다고 가정해봅시다.
(App.js)
import Detail from "./routes/Detail";
let [shoes, setShoes] = useState(data)
<Route path="/detail/0" element={ <Detail shoes={shoes}/> }/>
<Route path="/detail/1" element={ <Detail shoes={shoes}/> }/>
<Route path="/detail/2" element={ <Detail shoes={shoes}/> }/>
(Detail.js)
function Detail(props) {
return (
<div className="container>
<div className="row">
<div className="col-md-6">
<img src="https://codingapple1.github.io/shop/shoes1.jpg" width="100%" />
</div>
<div className="col-md-6 mt-4">
<h4 className="pt-5">{props.shoes[0].title}</h4>
<p>{props.shoes[0].content}</p>
<p>{props.shoes[0].price}원</p>
<button className="btn btn-danger">주문하기</button>
</div>
</div>
</div>
);
};
export default Detail;
이런식으로 만들 수 있겠지만, 이럴 경우, 나중에 상세페이지들의 개수가 많아질때 문제가 생깁니다.
이럴 때, URL 파라미터라는 문법을 사용가능합니다.
URL 파라미터 문법은 페이지의 주소를 정의할때, 유동적인 값을 전달하기 위한 문법입니다.
<Route path="/detail/:id" element={ <Detail shoes={shoes}/> }/
페이지를 여러개 만들고 싶으면 URL 파라미터라는 문법을 사용가능합니다.
path 작명할 때 /:어쩌구 이렇게 사용하면 "아무 문자"를 뜻합니다.
그래서 위의 <Route>는 누군가 주소창에 /detail/아무거나 입력했을 때<Detail> 컴포넌트 보여달라는 뜻입니다.
이렇게 페이지를 여러개 만들어 놨지만, 접속해보면 다 똑같은 0번째 상품명만 보여주고 있습니다.
왜냐면 0번째 상품명 보여달라고 코드를 작성해놓았기 때문입니다.
(Detail.js)
<h4 className="pt-5">{props.shoes[현재url에입력된숫자].title}</h4>
<p>{props.shoes[0].content}</p>
<p>{props.shoes[0].price}원</p>
<button className="btn btn-danger">주문하기</button>
0이라고 하드코딩해놨던 자리에 현재 url파라미터에 입력된숫자를 넣는겁니다.
그럼 /detail/1로 접속하면 1번째 상품명을 보여줄 수 있습니다.
현재 url파라미터에 입력된숫자를 가져오기 위해 사용하는 react-router 에서 제공하는 HOOK인 useParams() 입니다.
import { useParams } from 'react-router-dom'
function Detail(){
let {id} = useParams();
console.log(id)
return (
<div className="container>
<div className="row">
<div className="col-md-6">
<img src="https://codingapple1.github.io/shop/shoes1.jpg" width="100%" />
</div>
<div className="col-md-6 mt-4">
<h4 className="pt-5">{props.shoes[id].title}</h4>
<p>{props.shoes[0].content}</p>
<p>{props.shoes[0].price}원</p>
<button className="btn btn-danger">주문하기</button>
</div>
</div>
</div>
)
}
useParams() 라는 함수를 상단에서 import 해오면 쓸 수 있는데, 이거 쓰면 현재 /:url파라미터 자리에 유저가 입력한 값을 가져올 수 있습니다.
그래서 위처럼 사용하면
누가 /detail/1로 접속하면 id라는 변수에 1이 들어옵니다.
누가 /detail/2로 접속하면 id라는 변수에 2가 들어옵니다.
그래서 props.shoes[id].title 이러면 아까 의도했던 기능이 완성됩니다. 페이지마다 각각 다른 상품명이 보입니다.
응용사항 : 자료의 순서가 변경되면 상세페이지도 고장나는 문제는 어떻게 해결할까요?
상품 순서를 가나다순으로 변경하는 버튼을 만들어버렸다고 가정합시다.
그거 누르면 shoes라는 state 안의 상품이 가나다순으로 정렬됩니다. 그럼 0번째 state 값이 바뀌게 되어 상세페이지에서 보여주는 상품이 달라집니다.
이럴때는 현재 url에 입력한 번호와 같은 번호를 가진 상품을 찾아서 데이터바인딩 해달라고 코드짜면 끝일 것 같습니다
(Detail.js)
function Detail(props){
let { id } = useParams();
let 찾은상품 = props.shoes.find(function(x){
return x.id == id
});
return (
<div className="container">
<div className="row">
<div className="col-md-6">
<img src="https://codingapple1.github.io/shop/shoes1.jpg" width="100%" />
</div>
<div className="col-md-6 mt-4">
<h4 className="pt-5">{찾은상품.title}</h4>
<p>{찾은상품.content}</p>
<p>{찾은상품.price}원</p>
<button className="btn btn-danger">주문하기</button>
</div>
</div>
</div>
)
};
export default Detail
1. find()는 array 뒤에 붙일 수 있으며 return 조건식 적으면 됩니다. 그럼 조건식에 맞는 자료 남겨줍니다.
2. find() 콜백함수에 파라미터 넣으면 array자료에 있던 자료를 뜻합니다.
3. x.id == id 라는 조건식을 써봤습니다. 그럼 array자료.id == url에입력한번호 일 경우 결과를 변수에 담아줍니다.
그럼 {상품1개} 이런거 남을듯요 출력해봅시다.
4. 마지막으로 찾은 {상품1개}를 html에 데이터바인딩해놨습니다.
출처 : 코딩애플 "React 리액트 기초부터 쇼핑몰 프로젝트까지!"
'React' 카테고리의 다른 글
리액트 React : Lifecycle과 useEffect (1) | 2024.03.27 |
---|---|
리액트 React : styled-components (0) | 2024.03.26 |
리액트 React : Module, import 및 export (0) | 2024.03.25 |
리액트 React : 리액트 환경에서 동적인 UI 만드는 법 (0) | 2024.03.25 |
리액트 React : Component와 props (1) | 2024.03.23 |