[감정 일기장] 앱을 만들기 위한 순서는 다음과 같다.
[감정 일기장]은 일기를 작성하면서 그날의 자기감정을 표현하는 서비스이다.
총 4페이지로 구성되어 있다.
상단 헤더 섹션: 월 단위로 일기를 조회하는 기능, 좌우 버튼을 클릭하면 월 단위로 날짜를 이동한다.
일기 리스트 섹션: '최신순', '오래된 순'으로 일기 리스트를 정렬하는 기능, 새로운 일기를 추가하는 기능이 있다.
<새 일기 쓰기> 버튼을 누르면 새로운 일기를 작성하는 New 페이지로 이동한다.
사용자가 New 페이지에서 일기를 작성하고 <작성 완료> 버튼을 누르면, Home으로 돌아간다.
이때 작성한 일기가 Home 페이지의 리스트에 추가된다.
Home에서 일기 리스트를 조회한 다음, 특정 일기를 클릭하면 Diary 페이지로 이동한다.
이런 페이지를 상세 / 콘텐츠 페이지라고 한다.
import "./App.css";
function App() {
return <div className="App"></div>;
}
export default App;
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
[감정 일기장] 프로젝트에 적용할 폰트를 설정한다.
웹 폰트: 특정 URL로 폰트를 가져오는 방식이다.
@import url("https://fonts.googleapis.com/css2?family=Nanum+Pen+Script&family=Yeon+Sung&display=swap");
body {
font-family: "Nanum Pen Script";
margin: 0px;
}
App.js를 다음과 같이 수정한다.
import "./App.css";
function App() {
return (
<div className="App">
<h1>감정 일기장</h1>
</div>
);
}
export default App;
두 폰트 모두 잘 불러와지는지 확인해 본다.
(...)
body {
font-family: "Yeon Sung";
margin: 0px;
}
[감정 일기장] 프로젝트에서 사용할 이미지를 다운로드하여 페이지에 렌더링 하는 방법을 알아보자.
https://github.com/winterlood/one-bite-react/releases/tag/emotion
다음 링크에 접속하여 emotion.zip을 다운로드한다.
src에 img 폴더를 생성하고 파일명 그대로 저장한다.
App.js를 다음과 같이 수정한다.
import emotion1 from "./img/emotion1.png";
function App() {
return (
<div className="App">
<img alt="감정1" src={emotion1} />
</div>
);
}
export default App;
src 폴더에서 util.js 파일을 만들고 다음과 같이 작성한다.
import emotion1 from "./img/emotion1.png";
import emotion2 from "./img/emotion2.png";
import emotion3 from "./img/emotion3.png";
import emotion4 from "./img/emotion4.png";
import emotion5 from "./img/emotion5.png";
export const getEmotionImgById = (emotionId) => {
const targetEmotionId = String(emotionId);
switch (targetEmotionId) {
case "1":
return emotion1;
case "2":
return emotion2;
case "3":
return emotion3;
case "4":
return emotion4;
case "5":
return emotion5;
default:
return null;
}
};
App 컴포넌트에서 함수 getEmotionImgById를 호출해 모든 감정 이미지를 페이지에 렌더링 한다.
import { getEmotionImgById } from "./util";
function App() {
return (
<div className="App">
<img alt="감정1" src={getEmotionImgById(1)} />
<img alt="감정2" src={getEmotionImgById(2)} />
<img alt="감정3" src={getEmotionImgById(3)} />
<img alt="감정4" src={getEmotionImgById(4)} />
<img alt="감정5" src={getEmotionImgById(5)} />
</div>
);
}
export default App;
리액트 앱을 구성할 때 꼭 필요한 '페이지 라우팅'의 개념을 알아보자.
페이지 라우팅이 무엇인지 단계적으로 알아보자.
경로를 의미하는 Route와 진행을 뜻하는 ing가 합쳐진 단어로, '경로를 지정하는 과정'이라는 뜻이다.
데이터 전달을 목적으로 최적의 경로를 찾아 데이터를 전송하는 과정이다.
요청에 따라 적절한 페이지를 반환하는 일련의 과정이다.
URL 요청 경로에 맞게 적절한 페이지를 보여주는 과정이다.
해당 프로젝트에서는 브라우저에서 페이지를 만드는 클라이언트 사이드 렌더링 방식을 사용한다.
해당 페이지 라우팅을 서버 사이드 렌더링이라고 한다.
해당 방식은 웹 브라우저에 표시할 페이지를 웹 서버에서 만들어 전달한다.
해당 페이지 라우팅을 클라이언트 사이드 렌더링이라고 한다.
해당 방식은 페이지를 브라우저가 직접 만든다.
npm i react-router-dom
index.js를 다음과 같이 작성한다.
(...)
import { BrowserRouter } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
BrowserRouter에는 브라우저의 주소 변경을 감지하는 기능이 있다.
src 아래에 pages 폴더를 생성한다.
pages 폴더에 Home.js를 만들고 다음과 같이 작성한다.
const Home = () => {
return <div>Home 페이지입니다</div>;
};
export default Home;
pages 폴더에 New.js를 만들고 다음과 같이 작성한다.
const New = () => {
return <div>New 페이지입니다</div>;
};
export default New;
pages 폴더에 Diary.js를 만들고 다음과 같이 작성한다.
const Diary = () => {
return <div>Diary 페이지입니다</div>;
};
export default Diary;
pages 폴더에 Edit.js를 만들고 다음과 같이 작성한다.
const Edit = () => {
return <div>Edit 페이지입니다</div>;
};
export default Edit;
App.js를 다음과 같이 수정한다.
import { Routes, Route } from "react-router-dom";
import "./App.css";
import Home from "./pages/Home";
import New from "./pages/New";
import Diary from "./pages/Diary";
import Edit from "./pages/Edit";
function App() {
return (
<div className="App">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/new" element={<New />} />
<Route path="/diary" element={<Diary />} />
<Route path="/edit" element={<Edit />} />
</Routes>
</div>
);
}
export default App;
Routes는 자신이 감싸는 Route 컴포넌트 중에서
브라우저 주소 표시줄에 입력된 URL 경로와 일치하는 요소를 찾아 페이지에 렌더링 한다.
App.js를 다음과 같이 수정한다.
import { Routes, Route, Link } from "react-router-dom";
(...)
function App() {
return (
<div className="App">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/new" element={<New />} />
<Route path="/diary" element={<Diary />} />
<Route path="/edit" element={<Edit />} />
</Routes>
<div>
<Link to={"/"}>Home</Link>
<Link to={"/new"}>New</Link>
<Link to={"/diary"}>Diary</Link>
<Link to={"/edit"}>Edit</Link>
</div>
</div>
);
}
export default App;
동적 경로: 특정 아이템을 나타내는 id처럼 값이 변하는 요소를 URL에 포함하는 경우이다.
https://localhost:3000/diary/{id}
예시) id가 3인 일기 상세 페이지의 URL
-> https://localhost:3000/diary/3
https://localhost:3000?sort=latest
https://localhost:3000?sort=latest&page=1
App 컴포넌트에서 다음 부분을 수정한다.
<Route path="/diary/:id" element={<Diary />} />
Diary.js를 다음과 같이 수정한다.
import { useParams } from "react-router-dom";
const Diary = () => {
const params = useParams();
console.log(params);
return <div>Diary 페이지입니다</div>;
};
export default Diary;
Diary.js를 다음과 같이 수정한다.
import { useParams } from "react-router-dom";
const Diary = () => {
const { id } = useParams();
return (
<div>
<div>{id}번 일기</div>
<div>Diary 페이지입니다</div>
</div>
);
};
export default Diary;
Home 컴포넌트를 다음과 같이 수정한다.
import { useSearchParams } from "react-router-dom";
const Home = () => {
const [searchParams, setSearchParams] = useSearchParams();
console.log(searchParams.get("sort"));
return <div>Home 페이지입니다</div>;
};
export default Home;
<Routes>
<Route path="/" element={<Home />} />
<Route path="/new" element={<New />} />
<Route path="/diary" element={<Diary />} />
<Route path="/edit" element={<Edit />} />
</Routes>
@import url("https://fonts.googleapis.com/css2?family=Nanum+Pen+Script&display=swap");
body {
font-family: "Nanum Pen Script";
margin: 0px;
}
2.
<Routes>
<Route path="/" element={<Home />} />
<Route path="/new" element={<New />} />
<Route path="/diary" element={<Diary />} />
<Route path="/edit" element={<Edit />} />
</Routes>
<div>
<Link to={"/"}>Home</Link>
<Link to={"/new"}>New</Link>
<Link to={"/diary"}>Diary</Link>
<Link to={"/edit"}>Edit</Link>
</div>
이정환, 『한 입 크기로 잘라먹는 리액트』, 프로그래밍인사이트(2023).
Editor: 숨숨
[리액터 스타터2] 리덕스(Redux) (0) | 2024.01.19 |
---|---|
[리액터 스타터2] 9장. 컴포넌트 트리에 데이터 공급하기 (0) | 2024.01.05 |
[리액터 스타터2] 7장. useReducer와 상태 관리 / 8장. 최적화 (2) | 2023.12.29 |
[리액터 스타터2] project 2 [할 일 관리] 앱 만들기 2 (0) | 2023.12.23 |
[리액터 스타터2] project 2 [할 일 관리] 앱 만들기 1 (0) | 2023.12.01 |