Search

React 실습하기 2탄

Status
UPLOADING
Date
2024/03/11
Tags
React

1. Router

우선 Router 기능을 구현하기 위해서는 npm install react-router-dom 명령어를 통해 해당 라이브러리를 추가해주어야 합니다.
App.js
import Day from './component/Day'; import DayList from './component/DayList'; import EmptyPage from './component/EmptyPage'; import Header from './component/Header'; import { BrowserRouter, Route, Routes } from 'react-router-dom'; function App() { return ( <BrowserRouter> <div className="App"> <Header /> <Routes> <Route exact path="/" element={<DayList />}></Route> <Route path="/day/:day" element={<Day />}></Route> <Route path="*" element={<EmptyPage/>} /> </Routes> </div> </BrowserRouter> ); } export default App;
Java
복사
위 코드와 같이 구성하면 <Routes> 내부에 있는 태그들은 URL 경로에 따라 변경되는 컴포넌트 들이며, 외부에 있는 컴포넌트들은 그대로 유지될 것입니다.
따라서 Header 컴포넌트들은 유지되고, 정확하게 / 경로로 들어온다면 DayList 컴포넌트가, DayList에서 선택한 day는 /day/:day:day에 들어가 요청에 맞는 값들을 보여줄 것입니다.
그 외에 경로는 모두 EmptyPage 컴포넌트가 필터링 해줄 것입니다.
+ exact path를 사용한 이유는 “/” 경로를 제외한 그 어떤 경로에도 <DayList> 이외의 컴포넌트가 나타나지 않게 하기 위해서입니다. 만약 exact 속성이 아니라면 /가 포함된 모든 경로에 DayList 컴포넌트가 포함됩니다.
DayList.js
import { Link } from 'react-router-dom'; import dummy from '../db/data.json'; export default function DayList() { return ( <ul className="list_day"> {dummy.days.map((day) => ( <li key={day.id}> <Link to = {`/day/${day.day}`}> Day {day.day} </Link> </li> ))} </ul> ); }
Java
복사
<a> 대신 <Link> 를 사용했습니다.
Day.js
import dummy from "../db/data.json" import { useParams } from 'react-router-dom'; export default function Day() { const {day} = useParams(); const wordList = dummy.words.filter(word => word.day === Number(day)) return <> <h2> Day {day} </h2> <table> <tbody> {wordList.map(word => ( <tr key = {word.id}> <td>{word.eng}</td> <td>{word.kor}</td> </tr> ))} </tbody> </table> </> }
Java
복사
:day로 넘겨지는 값은 useParams를 통해 낚아채줍니다. 해당 day는 필터링 함수를 통해 각 일자에 맞는 단어 리스트를 추출하는 역할을 합니다.

2. 리팩토링

import dummy from "../db/data.json" import { useParams } from 'react-router-dom'; export default function Day() { const {day} = useParams(); const wordList = dummy.words.filter(word => word.day === Number(day)) return <> <h2> Day {day} </h2> <table> <tbody> {wordList.map(word => ( <tr key = {word.id}> <td> <input type="checkbox"/> </td> <td>{word.eng}</td> <td>{word.kor}</td> <td> <button>뜻 보기</button> <button class="btn_del">삭제</button> </td> </tr> ))} </tbody> </table> </> }
Java
복사
체크 박스와 뜻 보기, 삭제 버튼을 추가했다고 가정해봅시다.
뜻 보기를 누르면 해당 단어에 대한 뜻만 안보여야 합니다. 리액트 컴포넌트의 state 값은 각 컴포넌트 마다 별도로 구성됩니다. 따라서 각 행을 컴포넌트로 분리하는 작업이 필요합니다.
Word.js
import { useState } from 'react'; export default function Word({ word }) { // 초기값 const [isShow, setIsShow] = useState(false); // 초기값 const [isDone, setIsDone] = useState(word.isDone); function toggleDone() { setIsDone(!isDone); } function toggleShow() { setIsShow(!isShow); } return ( <tr className={isDone ? 'off' : ""}> <td> <input type="checkbox" checked = {isDone} onChange={toggleDone}/> </td> <td>{word.eng}</td> <td>{isShow && word.kor}</td> <td> <button onClick={toggleShow}>{isShow ? '숨기기' : '보기'}</button> <button className="btn_del">삭제</button> </td> </tr> ); }
Java
복사
이 쯤에서 한번 state 값과 function에 대해 다시 한번 짚고 넘어가야 할 것 같습니다.
const [isShow, setIsShow] = useState(false);
isShow: 상태 변수로, 초기 값은 false입니다. 이 변수는 어떤 요소의 표시 여부를 나타내는 데 사용될 수 있습니다.
setIsShow: 이 함수는 isShow 상태를 업데이트하는 데 사용됩니다. 새로운 값이 필요할 때 setIsShow를 호출하여 isShow의 값을 변경할 수 있습니다.
useState(false): useState 훅을 호출하며, isShow의 초기 값으로 false를 설정합니다.
function toggleShow() { setIsShow(!isShow); }
toggleShow 함수는 isShow 상태의 값을 반전시키는 함수입니다. isShowtrue이면 false로, false이면 true로 변경합니다. 이 함수를 호출함으로써 특정 요소의 표시 상태를 토글할 수 있습니다.
useState 훅은 컴포넌트가 렌더링될 때마다 현재 상태 값을 제공하므로, toggleShow 함수 내에서 isShow를 사용할 때, 그 시점에서의 isShow의 현재 값(즉, 가장 최근에 설정된 상태 값)을 참조하게 됩니다.

3. 간단하게 JSON Server 띄우기

npm install -g json-server
설치가 된 후 다음 명령어를 쳐봅시다.
json-server --watch ./src/db/data.json --port 3001
그러면 DB에 있는 두 days, words를 기반으로 한 EndPoint가 만들어집니다.
POST, GET, PUT, DELETE를 통해 CRUD 작업이 가능합니다.

4. REST API 적용하기

import { useParams } from 'react-router-dom'; import Word from './Word'; import { useEffect, useState } from 'react'; export default function Day() { const {day} = useParams(); const [words, setWords] = useState([]); useEffect(() => { fetch("http://localhost:3001/words") .then(res => { return res.json(); }) .then(words => { setWords(words) }) }) const wordList = words.filter(word => word.day === Number(day)) return <> <h2> Day {day} </h2> <table> <tbody> {wordList.map(word => ( <Word word={word} key={word.id}/> ))} </tbody> </table> </> }
Java
복사
이 부분은 다음과 같이 변경가능하다
// 변경 전 useEffect(() => { fetch("http://localhost:3001/words") .then(res => { return res.json(); }) .then(words => { setWords(words) }) }) const wordList = words.filter(word => word.day === Number(day)) // 변경 후 const {day} = useParams(); const [words, setWords] = useState([]); useEffect(() => { fetch(`http://localhost:3001/words?day=${day}`) .then(res => { return res.json(); }) .then(data => { setWords(data) }) }, [day]); // 여기 의존성 부분을 더 공부해야된다
Java
복사