5시쯤 되니 정신이 혼미해진다... 흠냐.
13장. 리액트 라우터로 SPA 개발하기
13-1) SPA란?
React의 핵심! 꽃! 스파!
SPA는 Single Page Application의 약자로, 한 개의 페이지로 이뤄진 애플리케이션이란 의미.
React와 같은 라이브러리 or 프레임워크를 통해 우선 애플리케이션을 브라우저에 불러와 실행시킨 후,
사용자와의 상호작용이 발생하면 필요한 부분만 JS를 이용해 업데이트 해주는 방식!
그런데 한 개의 페이지라면... 이용자에게 보이는 화면도 하나뿐인 것 아닌가?
→ No! 서버에서 사용자에게 제공하는 페이지는 한 종류이지만
해당 페이지에서 로딩된 JS와, 현재 사용자 브라우저의 주소 상태에 따라 다양한 화면을 보여줄 수 있다.
이렇게 다른 주소에 다른 화면을 보여주는 것을 라우팅이라고 한다!
React 라이브러리 자체에 이 기능이 내장되지 았지는 않지만
브라우저의 API를 직접 사용해 이를 관리하거나, 라이브러리를 사용해 이를 더욱 쉽게 구현할 수 있다.
(여기서는 사용 빈도가 가장 높은 리액트 라우터 를 사용할 예정)
하지만 이로 인한 문제!
JS를 실행하지 않는 일반 크롤러에서는 페이지를 정보를 제대로 수집해가지 못한다.
(즉 구글, 네이버와 같은 검색 엔진의 검색 결과에 노출이 잘 되지 않을수도)
또한 JS가 실행될 때까지 페이지에 비어있기 때문에 로딩되어 실행되는 짧은 시간 동안 흰 페이지가 나타날 수도 있다.
→ 이후에 배울 서버 사이드 렌더링을 통해 모두 해결 가능! 와우!
13-2) 프로젝트 준비 및 기본 사용법 익히기
실습을 통해 쫌 더 감을 익혀보자!
전체 흐름은...
1. 프로젝트 생성 및 리액트 라우터 적용
2. 페이지 만들기
3. Route 컴포넌트로 특정 주소에 컴포넌트 연결
4. 라우트 이동하기
5. URL 파라미터와 쿼리 이해하기
6. 서브 라우트
7. 부가기능 알아보기
길기도 하구만!
1. 프로젝트 생성 및 라이브러리 설치
React 프로젝트도 하나 만들고,
리액트 라우터도(react-router-dom)도 설치해주자.
2. 프로젝트에 라우터 적용
프로젝트에 리액트 라우터를 적용할 때는...
ReactDom.render를(컴포넌트를 페이지에 렌더링 하는 역할) 사용하고 있는 index.js 파일을 수정!
index.js
react-router-dom에 내장되어 있는 BrowserRouter라는 컴포넌트를 사용해 감싸주자!
요 녀석은 페이지를 새로고침하지 않고도 주소를 변경하고,
현재 주소에 관련된 정보를 props로 쉽게 조회하거나 사용할 수 있도록 돕는다.
아직은 뭐... 별반 달라진 걸 모르겠다!
3. 페이지 만들기
라우트로 사용할 페이지 컴포넌트를 만들 차례.
Home 컴포넌트(맨 처음 보여줌)와 About 컴포넌트(웹 사이트를 소개)를 만들어보자!
Home.js
About.js
참 평화로운 코드다.
4. Route 컴포넌트로 특정 주소에 컴포넌트 연결
Route 라는 컴포넌트를 사용해 사용자의 현재 경로에 따라 다른 컴포넌트를 보여 줄 수 있다!
사용 방식은...
요렇게! 참 간단해보인다.
App.js
쨔잔. Django의 향기가 느껴지면서 마음이 편안해진다.
우와! url에 따라 다른 컴포넌트가 나오기...는 하는데...
Home과 About 컴포넌트가 모두 나타난다!
왜? → /about 이라는 경로가 / 규칙에도 일치하기 때문에!
이러면 안되는 거 아닌가? /about에는 About 컴포넌트만 나왔으면 좋겠다!
Home 컴포넌트에서 exact라는 props를 true로 설정해 해결할 수 있다!
쨘. 이제 잘 뜨는구만.
5. Link 컴포넌트를 사용해 다른 주소로 이동하기
Link컴포넌트 → 클릭하면 다른 주소로 이동시켜 주는 컴포넌트!
그냥 a 태그를 사용하면 안되나..?
그냥 a 태그를 사용하면 안되나..?
a 태그는 페이지 전환 과정에서 페이지를 새로 불러오기 때문에
애플리케이션이 들고 있는 상태들을 몽땅 날려버리게 된다!
즉 애플리케이션이 들고 있던 상태들을 모두 날려버리면서,
렌더링 된 컴포넌트들도 모두 사라지고 처음부터 렌더링이 이뤄지고 만다!
따라서 리액트 라우터에서는 a 태그 X
그냥 a 태그를 사용하면 안되나..?
a 태그는 페이지 전환 과정에서 페이지를 새로 불러오기 때문에
애플리케이션이 들고 있는 상태들을 몽땅 날려버리게 된다!
즉 애플리케이션이 들고 있던 상태들을 모두 날려버리면서,
렌더링 된 컴포넌트들도 모두 사라지고 처음부터 렌더링이 이뤄지고 만다!
따라서 리액트 라우터에서는 a 태그 X
대신 리액트 라우터에는 Link 컴포넌트를 사용한다!
Link 컴포넌트를 사용해 페이지를 전환하면,
페이지를 새로 불러오지 않고 애플리케이션은 그대로 유지한 상태에서
HTML History API를 사용해 페이지의 주소만 변경해준다!
(물론 Link 컴포넌트 자체는 a 태그로 이루어져 있지만, 페이지 전환을 방지하는 기능이 내장)
사용은 이렇게! 역시 간단해보여서 좋다.
App.js
이렇게 써주면 된다!
컴포넌트만 샥샥 바뀐다! 정말 신기하다...!
13-3) Route 하나에 여러 개의 path 설정하기
여러 개의 path에 같은 컴포넌트를 보여 주고 싶다면?
→ 그냥 path 별로 Route 컴포넌트를 여러 개 만들면 되지 않나?
물론 그래도 되지만...
App.js
이렇게 path props를 배열로 설정해 넘겨주면, 여러 경로에서 같은 컴포넌트를 보여줄 수 있다.
13-4) URL 파라미터와 쿼리
페이지 주소를 정의할 때, 유동적인 값을 전달해야 할 때도 있다 → 파라미터 / 쿼리
- 파라미터 : ex) /profiles/velopert
- 쿼리 : ex) /about?detail=true
무조건적인 규칙은 없지만...
파라미터는 특정 아이디 or 이름을 사용해 조회할 때,
쿼리는 어떤 키워드를 검색하거나 페이지에 필요한 옵션을 전달할 때 사용한단다!
1. URL 파라미터
위 예시처럼 Profile 이란 페이지에서 파라미터를 사용할 예정!
Profile.js
그러기 위해 Profile 컴포넌트를 만들어줬다.
/Profile/velopert 처럼 뒷부분에 유동적인 username 값을 넣어줄 때 → 해당 부분을 props로 받아오도록!
Profile 컴포넌트는 match라는 객체를 받아오는데... ← 누구한테서 가져온 것?
요 녀석은 라우트로 사용되는 컴포넌트에서 전달!
match 객체 안의 params 값을 참고해 URL 파라미터를 사용할 수 있다.
조금 더 추가적인 설명을 하자면...
라우팅 한 컴포넌트들은 history, location, match 라는 세 가지 읽기 전용 데이터를 가진다.
이 중 match 객체 안에는 현재 컴포넌트가 어떤 경로 규칙에 의해 보이는지에 대한 정보가 들어있다.
그럼 params는 뭔디?
얘는 GET이나 POST 요청을 통해 전달되는 파라미터!(즉 주소 끝에 붙는 녀석들)
즉 URL 요청 속 params가 data 안에 있으면,
해당 params({username}), data 속 요청 받은 params에 해당되는 유저의 이름({profile.name}) 등을 띄워준 것.
App.js
App에서는 이렇게 사용!
Link를 통해 명시된 URL로 이동시키고, Route의 path 규칙에는 :username을 붙여줬다!
신기하게 잘 뜬다(URL 파라미터에 주목하자)
2. URL 쿼리
About 페이지에서는 URL 쿼리를받을 예정.
쿼리는 앞서 말한 라우팅 한 컴포넌트의 데이터 중 location 객체의 search 값에서 조회할 수 있다.
(location 객체에는 웹 애플리케이션의 현재 주소에 대한 정보가 담겨 있다 - JS에서 본 듯?!)
location 객체는 다음과 같은 형태!
URL 쿼리를 읽을 때는 이중 search의 값을 확인하면 된다!
그런데 요 search는 문자열 형태 → 여기서 특정 값을 읽어 오기 위해서는 문자열을 객체 형태로 변환해야한다!
이 때 사용되는 라이브러리가 qs. 설치해주자!
이제 About이란 컴포넌트를 만들고, loaction.search 값의 detail이 true인지 아닌지에 따라 추가 정보를 보여줄 예정!
About.js
또잉.
우선 location.search(쿼리 문자열)를 qs.parse를 통해 객체 형태로 변환!
(ignoreQueryPrefix: true를 통해 문자열 맨 앞의 ?를 생략해준다)
이 때 쿼리 문자열을 객체로 파싱하는 과정에서 결과 값은 언제나 문자열이다!
즉 ?value=1 or ?value=true 라고 적는다하더라도....
qs.parse를 거친 결과값은 "1" or "true"가 되는 것!
따라서 숫자를 받아 올 경우 parseInt 함수를 사용했는지를,
논리 자료형 값을 사용하는 경우 "true"라는 문자열과 일치하는지를 주의해야 한다.
해당 URL 요청을 보내면 About 컴포넌트가 잘 나타난다!
13-5) 서브 라우트
서브 라우트란? 라우트 내부에 또 라우트를 정의하는 것!
Profiles.js
흐아. 이는 또 무슨 소린고 하니...
첫 번째 Route 컴포넌트에는 component 대신 render라는 props를 넣어줬다!
이를 통해 보여주고 싶은 JSX를 넣어 보여줄 수 있는 것.
(이 녀석마저 컴포넌트로 만들기에는... 크기도 작고 기능도 없으니까!)
또한 JSX에서 props를 설정할 때 값을 생략하면 자동으로 true로 설정된다!
즉 Profiles 컴포넌트를 통해 프로필 링크를 보여주고, 이 안에서 Profile 컴포넌트를 서브 라우트로 사용한 것!
App.js
쨘. 기존 App 컴포넌트 속 프로필 링크를 지우고, Profiles 컴포넌트를 /profiles 경로에 연결시켜 줬다.
13-6) 리액트 라우터 부가 기능
1. history
history 객체는 라우트로 사용된 컴포넌트에 match, location과 함께 전달되는 props!
얘를 통해 컴포넌트 내에 구현하는 메서드에서 라우터 API를 호출할 수 있다.
(ex 특정 버튼 눌렀을 때 뒤로가기, 로그인 후 화면 전환하기, 다른 페이지 이탈 방지하기)
HistorySample.js
history 객체를 이용한 모습!
페이지를 떠날 때 block 시키는 부분이 특이한데...
HistorySample 컴포넌트에서 history.block("떠나실~")을 history.unblock으로 할당!
useEffect를 이용해 HistorySample에 변화가 생기면 해당 함수를 실행시켜줬다.
해당 페이지에서 나가려고 하면 브라우저 메시지 창이 뜬다!
3. Switch
JS의 Switch문...이 아니라! react-router-dom의 Switch 컴포넌트!
요 녀석은 여러 Route를 감싸서 그 중 일치하는 단 하나의 라우트만을 렌더링시킨다.
이를 이용해 모든 규칙과 일치하지 않을 때 보여 줄 Not Found 페이지도 구현 가능!
App.js
이렇게!
path를 따로 정의하지 않을 경우 모든 상황에 렌더링된다.
따라서 존재하지 않는 페이지일 경우 해당 라우터가 작동!
4. NavLink
얘는 Link와 유사하다!
현재 경로와 Link에서 사용하는 경로가 일치할 경우, 특정 스타일 혹은 CSS 클래스를 적용할 수 있는 컴포넌트.
Profiles.js
다시 Profiles로 돌아와서...
NavLink에서 링크가 활성화되었을 때의 스타일을 적용할 때는 activeStyle 값을,
CSS 클래스를 적용할 때는 activeClassName 값을 props로 넣어주면 된다!
그럼 이렇게 선택되어 있는 경우 스타일이 적용된다!
또한 요 녀석은 '해당 링크가 활성화되있을 때'의 개념이기 때문에,
해당 링크로 갈 때마다(이름을 클릭할 때마다) CSS가 각각 적용되는 걸 볼 수 있다.
'source-code > React' 카테고리의 다른 글
리액트를 다루는 기술 _ 15장 (0) | 2021.03.18 |
---|---|
리액트를 다루는 기술 _ 14장 (0) | 2021.03.18 |
리액트를 다루는 기술 _ 12장 (0) | 2021.03.16 |
리액트를 다루는 기술 _ 11장 (0) | 2021.03.16 |
리액트를 다루는 기술 _ 10장 - 2 (0) | 2021.03.16 |