2주 차에는 라우팅, 스타일을 적용하는 과제가 주어졌다.
과제를 수행하면서 알아갔던 개념들을 정리해보려 한다.
✍️ 2주차 과제 내용
- 라우팅 적용하기
- styled-components 라이브러리를 활용하여 디자인 적용하기
라우팅이란?
라우팅이란 사용자가 요청한 URL에 따라 해당 URL에 맞는 페이지를 보여주는 것이다.
예를 들어, 쇼핑몰 애플리케이션은 장바구니, 마이페이지, 상품 상세 등 여러 페이지들이 존재한다.
페이지별로 컴포넌트들을 분리해 가면서 프로젝트를 관리하기 위해 필요한 것이 라우팅 시스템이다.
리액트에서는 주로 리액트 라우터(React Router)를 사용하여 라우팅을 구현한다.
📃 React Router
설명
리액트 라우터를 사용하면 *싱글 페이지 애플리케이션(SPA, Single Page Application)을 만들 수 있다.
*싱글 페이지 애플리케이션
한 개의 페이지로 이루어진 애플리케이션
기존의 멀티 페이지 애플리케이션(MPA)은 사용자가 다른 페이지로 이동할 때마다 새로운 html을 받아오고, 페이지가 로딩될 때마다 서버에서 css, js, 이미지 등의 리소스를 전달받아 브라우저 화면에 보여주었다.
하지만 사용자에게 제공되는 정보가 많아질수록 이 방법이 적합하지 않았고, 이때 등장한 개념이 싱글 페이지 애플리케이션이다.싱글 페이지 애플리케이션은 리소스들을 처음 실행 시에 한 번만 받아와서 웹 애플리케이션을 실행시킨 후에 필요한 데이터만 새로 불러와 화면을 업데이트시켜준다.
따라서 사실상 한 페이지만 존재하지만, 사용자에게는 여러 페이지가 존재하는 것처럼 느낄 수 있다.
설치
# npm
npm install react-router-dom
# yarn
yarn add react-router-dom
기본 문법
// App.js
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import About from './pages/About';
import Home from './pages/Home';
const App = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
);
};
export default App;
BrowserRouter
를 상위 컴포넌트로 감싸고, Routes
안에 사용할 페이지들을 Route
로 하나씩 만들어준다.
path
에는 경로 설정을, element
에는 해당 경로에 보일 컴포넌트들을 설정한다.
라우터 컴포넌트의 종류
1) BrowserRouter - HTML5를 지원하는 브라우저의 주소를 감지한다.
2) HashRouter - 해시 주소를 감지한다.
// src/pages/Home.jsx
const Home = () => {
return <div>Home 입니다.</div>;
};
export default Home;
// src/pages/About.jsx
const About = () => {
return <div>About 입니다.</div>;
};
export default About;
애플리케이션이 시작될 때 처음 페이지는 Home 컴포넌트가 보이고, /about
경로에는 About 컴포넌트가 보인다.
💄 스타일링
리액트에서는 여러 가지 스타일링 방식이 존재한다.
- Inline Style CSS
- Import Style CSS
- CSS-in-JS
Inline Style CSS
style
속성을 사용하여 자바스크립트 객체를 스타일로 적용할 수 있다.
아래는 리액트 공식 문서에 나오는 예시이다.
const divStyle = {
color: 'blue',
backgroundImage: 'url(' + imgUrl + ')',
};
function HelloWorldComponent() {
return <div style={divStyle}>Hello World!</div>;
}
스타일 객체의 key는 DOM 노드의 프로퍼티에 접근하는 것과 일관성을 유지하기 위해 카멜 케이스(camel case)를 사용하여 작성한다.
Import Style CSS
외부에 *.css
파일을 정의하여 className을 통해 스타일을 적용한다.
// style.css
.main{
color: blue;
background-color: yellow;
}
import "./style.css";
function HelloWorldComponent() {
return <div className="main">Hello World!</div>;
}
CSS-in-JS
JavaScript 파일 내부에 css를 정의하여 결합하는 패턴이다.
React에서 포함된 기능이 아닌 별도의 라이브러리로 제공된다.
styled-components
, emotion
과 같은 스타일 라이브러리가 가장 많이 사용된다.
두 라이브러리의 전반적인 기능은 동일하며 큰 차이는 없지만, emotion을 사용하려면 JSX Pragma 라는 것을 설정해주어야 하는 귀찮음이 있어서 주로 styled-components를 사용하는 것 같다.
💅 Styled Components
설치
npm install --save styled-components
기본 문법
설치한 styled-components 패키지에서 styled
를 가져와서 스타일 컴포넌트를 생성하여 사용할 수 있다.
// Counter.jsx
import styled from "styled-components";
const Button = styled.button`
width: 200px;
height: 50px;
background-color: #eeeeee;
border: none;
border-radius: 10px;
padding: 10px;
cursor: pointer;
`;
const Counter = () => {
return <Button>+1</Button>;
};
export default Counter;
가변 스타일링
props에 따라 가변적인 스타일링도 가능하다.
이때 주의할 점은 스타일링 된 컴포넌트에도 props를 넘겨주어야 사용할 수 있다.
// App.js
import Counter from "./Counter";
export default function App() {
return (
<div>
<Counter upDown={"up"} />
<Counter upDown={"down"} />
</div>
);
}
// Counter.jsx
import styled from "styled-components";
const Button = styled.button`
width: 200px;
height: 50px;
background-color: ${(props) => (props.upDown === "up" ? "red" : "blue")};
color: white;
border: none;
border-radius: 10px;
padding: 10px;
cursor: pointer;
`;
const Counter = ({ children, upDown }) => {
return <Button upDown={upDown}>{children}</Button>;
};
export default Counter;
🤔 진행하면서 어려웠던 점
- 컴포넌트 이름 짓기
- react-router-dom을 사용하면서 gh-pages에서 발생하는 오류
컴포넌트 이름 짓기
컴포넌트를 봤을 때 해당 컴포넌트의 역할이 잘 보이게 이름을 짓는 것이 생각보다 어려웠다.
또한 버튼 두 개를 하나의 컴포넌트로 묶어서 표현할지, 각각의 컴포넌트로 둘지도 고민하게 되었는데 나의 경우에는 하나의 컴포넌트로 묶어서 표현해 보았다.
하나의 컴포넌트로 묶고 보니, 버튼 컴포넌트를 두 개 사용하는 것과 그렇게 큰 차이를 느끼지는 못했다.
따로 상태를 관리해야 하는 경우가 아니라면 굳이 묶을 필요는 없을 것 같다.
해당 깃헙 링크 - DetailMenuButton
이때, 버튼 두 개를 하나의 컴포넌트 내부에 만들어주었기 때문에 단수형이 아닌 복수형으로 작성하는 것이 좋겠다는 피드백을 받았다.
예를 들어 DetailMenuButton ➡️ DetailMenuButtons 혹은 DetailMenuTabs와 같이 여러 개가 들어있다는 것을 명시해 주면 코드를 좀 더 빠르고 쉽게 이해할 수 있다.
gh-pages 오류
해당 깃헙 링크 - ISSUE-#12
react-router v4에서는 BrowserRouter에 basename 속성을 이용하면 오류가 해결되는 것 같은데 v6에서는 해당 방법으로는 해결되지 않았다. (자세한 내용)
일단, gh-pages에서 react-router로 페이지를 이동할 때 오류가 발생하는 것은
github.io에서 HTML5 *pushState history API를 사용하는 router(BrowserRouter)를 지원하지 않기 때문이다.
HTML 문서에 브라우저의 세션 기록 스택에 항목을 추가한다.
페이지를 reload 하지 않고 주소만 변경할 때 사용하는 방식으로 SPA에서 많이 사용된다.
URL이 변경되면 해당 URL에 대한 서버를 요청하게 되는데 라우터를 지원하지 않아서 해당 경로를 찾지 못하기 때문에 결국에는 404 에러가 발생하게 된다.
따라서 이런저런 해결 방법을 찾아 해 봤지만 결국에는 HashRouter를 사용하여 해결하였다. (cra 공식문서)
HashRouter
현재 페이지의 경로 뒤에 #을 붙여, # 뒤에 내용 변경에는 리랜더링이 이루어지지 않도록 한다.
🧹 정리
현재는 프로젝트를 혼자 만들어나가고 있지만 협업을 위해서는 컴포넌트 이름부터 커밋까지 고려해야 할 세부적인 사항이 많다는 것을 느꼈다.
기존에는 하나의 커밋에 여러 가지 작업을 넣으면서 진행했더라면 이번에는 하나의 커밋에는 하나의 작업만 넣으려고 노력했던 것 같다.
생각보다 많아지는 커밋에 의구심을 가졌지만 실제로 코드가 수정된 부분을 보기가 수월했고, revert를 해보면서 커밋을 세분화하는 것의 장점을 느꼈다.
추후에 팀 프로젝트를 할 때 이번 주차의 내용이 많은 도움이 될 것 같다!
👇👇
'Retrospective' 카테고리의 다른 글
[회고] <코멘토> 프론트엔드 직무부트캠프 3회차 (0) | 2023.02.02 |
---|---|
[회고] <코멘토> 프론트엔드 직무부트캠프 1회차 (0) | 2023.01.04 |
[ 후기 ] 노마드 코더 CSS Layout 마스터 클래스 챌린지 16기 졸업! (0) | 2022.02.09 |