npm install -g json-server
: json 서버 다운로드json-server --watch ./src/db/data.json --port 3001
: 서버 실행import React, { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
const DayList = () => {
const [days, setDays] = useState([]);
useEffect(()=>{
fetch('http://localhost:3001/days') //json server의 주소
.then(res => {
return res.json() //결과를 json형식으로 받아옴
})
.then(data =>{
setDays(data)//days에 값을 넣어줌
})
}, [])//최초 한번만 실행되도록 -> 빈 배열
return (
<>
<ul className='list_day'>
{days.map(day => (
<li key = {day.id}>
<Link to={`/day/${day.day}`}>Day {day.day}</Link>
</li>
))}
</ul>
</>
);
};
export default DayList;
import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import Word from './Word';
const 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])// day값에 따라 다른 데이터를 받아오도록 함
return (
<>
<h2>Day {day}</h2>
<table>
<tbody>
{words.map(word => (
<Word word={word} key={word.id}/>
))}
</tbody>
</table>
</>
);
};
export default Day;
Custom Hooks
import React, { useEffect, useState } from 'react';
const useFetch = (url) => {
const [data, setData] = useState([]);
useEffect(()=>{
fetch(url)
.then(res=>{
return res.json();
})
.then(data=>{
setData(data)
})
},[url])
return data;
};
export default useFetch;
const [days, setDays] = useState([]);
useEffect(()=>{
fetch('http://localhost:3001/days')
.then(res => {
return res.json()
})
.then(data =>{
setDays(data)
})
}, [])//최초 한번만 실행되도록 -> 빈 배열
const days = useFetch('http://localhost:3001/days')
const words = useFetch(`http://localhost:3001/words?day=${day}`)
import React, { useState } from 'react';
const Word = ({word : w}) => {//파라메타를 word로 받으면 state변수와 겹치므로 w로 바꿔줌
const [word, setWord] = useState(w);
const [isShow, setIsShow] = useState(false);
const [isDone, setIsDone] = useState(word.isDone);
function toggleShow(){
setIsShow(!isShow)
}
function toggleDone(){
// setIsDone(!isDone)
fetch(`http://localhost:3001/words/${word.id}`,{
method : 'PUT', // PUT 메소드 사용
headers : {
'Content-Type' : 'application/json' // JSON 형식으로 보냄
},
body : JSON.stringify({
...word, // 기존의 words 데이터에 isDone만 바꿔 바디로 보냄
isDone:!isDone
})
}).then(res=>{
if(res.ok){ // 정상적으로 update됐을 경우 isDone변수 또한 바꿔줌
setIsDone(!isDone)
}
})
}
function del(){
if(window.confirm('삭제하시겠습니까?')){
fetch(`http://localhost:3001/words/${word.id}`,{
method : 'DELETE' //DELETE 메소드 사용
}).then(res=>{
if(res.ok){
setWord({id : 0})//정상적으로 삭제됐을 경우 word의 id를 0으로 바꿔줌
}
})
}
}
if (word.id === 0){
return null; // id가 0일 때 null을 리턴하도록 함
}
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' onClick={del}>삭제</button>
</td>
</tr>
);
};
export default Word;
import React, { useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import useFetch from '../hooks/useFetch';
const CreateWord = () => {
const days = useFetch('http://localhost:3001/days');
const navigate = useNavigate();
function onSubmit(e){
e.preventDefault();//버튼을 눌러도 새로고침이 되지않음
fetch(`http://localhost:3001/words`,{
method : 'POST',//pos방식으로 데이터 추가
headers : {
'Content-Type' : 'application/json'
},
body : JSON.stringify({
day : dayRef.current.value, //input태그의 value값을 넣어줌
eng : engRef.current.value,
kor : korRef.current.value,
isDone : false
})
}).then(res=>{
if(res.ok){
alert('생성이 완료되었습니다.'); // 생성이 완료되었다는 알림이 뜨도록 alert창 띄워줌
navigate(`/day/${dayRef.current.value}`) //화면이 생성된 날짜의 페이지로 이동되도록 저장
}
})
}
const engRef = useRef(null);//dom에 접근할 수 있게 해줌 (ex : 스크롤 위치 확인, 포커스 줄 때 사용)
const korRef = useRef(null);
const dayRef = useRef(null);
return (
<form onSubmit={onSubmit}>
<div className='input_area'>
<label>Eng</label>
<input type='text' placeholder='computer' ref ={engRef}/>
</div>
<div className='input_area'>
<label>Kor</label>
<input type='text' placeholder='컴퓨터' ref = {korRef}/>
</div>
<div className='input_area'>
<label>Day</label>
<select ref={dayRef}>
{days.map(day=>( // data의 day값을 가져와 option으로 선택할 수 있도록 함
<option key={day.id} value={day.day}>{day.day}</option>
))}
</select>
</div>
<button>저장</button>
</form>
);
};
export default CreateWord;
import React from 'react';
import { useNavigate } from 'react-router-dom';
import useFetch from '../hooks/useFetch';
const CreateDay = () => {
const days = useFetch('http://localhost:3001/days');
const navigate = useNavigate();
function addDay(){
fetch(`http://localhost:3001/days`,{
method : 'POST',
headers : {
'Content-Type' : 'application/json'
},
body : JSON.stringify({
day : days.length + 1 //기존의 day 개수에 1을 추가
})
}).then(res=>{
if(res.ok){
alert('생성이 완료되었습니다.');
navigate('/'); // 홈화면으로 돌아오도록 함
}
})
}
return (
<div>
<h3>현재 일수 : {days.length}일</h3>
<button onClick={addDay}>Day 추가</button>
</div>
);
};
export default CreateDay;
if(days.length===0){
return <span>Loading...</span>
}
{words.length === 0 && <span>Loading...</span>}