voca프로젝트 - 2. CRUD 구현

김태은·2022년 6월 7일
0

리액트

목록 보기
3/3

Json-server

REST API

1. SELECT

  • GET 메소드 사용
  • DayList.js에 적용
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;
  • Day.js에 적용
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

  • 반복되는 코드들 custom hooks를 사용해 없애줌
  • hooks 폴더를 생성한 뒤 useFetch.js 작성
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;
  • DayList.js에 적용
 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')
  • Day.js에도 마찬가지로 적용
    const words = useFetch(`http://localhost:3001/words?day=${day}`)

2. UPDATE, DELETE

  • UPDATE
    • PUT 메소드 사용
    • word 데이터의 isDone 속성을 update하도록 함
  • DELETE
    • DELETE 메소드 사용
    • word 데이터를 삭제하도록 함
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;

3. INSERT

  • POST 메소드 사용
  • component에 CreateWord.js 추가
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;
  • CreateDay.js 추가
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;

로딩중 화면 만들기

  • 검사 -> network -> slow 3G
  • DayList.js에 추가
 if(days.length===0){
        return <span>Loading...</span>
    }
  • Day.js에 추가
{words.length === 0 && <span>Loading...</span>}

0개의 댓글