[React 입문] 생성(Create), 읽기(Read), 업뎃(Update),삭제(delete)

2021. 7. 12. 23:46front-end/React

// Create - POST

//Read - GET

//Update - PUT

//Delete - DELETE

 

나는 지금 단어장을 만들면서 단어의 생성, 읽기, 업뎃, 삭제에 대해 배우고 있고, 데이터 값은 json 형식으로 가져오고,

진짜 서버를 이용하는 것이 아니라, json-server 를 이용해 dummy data(?) 를 useFetch( )로 가져오는 것까지 했었다.

  1.  PUT  우선  해당 날짜에 있는 단어리스트들의 체크박스에 체크하면 체크한 값이 새로고침(F5) 했을 시에도 유지되도록 해줬다. 실제 data.json 에서 데이터 값이 삭제되게끔 해주었다. 

// import dummy from '../db/data.json';
import { useState } from 'react'; 
export default function Word({ word: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',
            headers:{//Content-Type 은 보내는 리소스의 타입을 의미
                'Content-Type' : 'application/json',
            },
            body :JSON.stringify({//json 문자열로 반환하기 위해 사용
                ...word,
                isDone: !isDone,
            }),
        }).then( res => { //응답 OK 이면 state 를 if 조건문
            if(res.ok){
                setIsDone(!isDone);
            }
        });
    }

   

    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>
    );
}

// Create - POST
//Read - GET
//Update - PUT
//Delete - DELETE

fetch ( ( url 경로 ),{ } ) 문법 안에

 method :

Method는 HTTP method와 동일한 스팩으로 들어가면 된다. GET/POST/HEAD/PUT/DELETE/OPTION/PATH 등등

headers: headers 는 Request Header를 지정해주는 곳인데, 2가지 형식으로 넣을 수 있다.
Object lireral과 Headers 객체의 인스턴스를 넣을 수 있다.

body : body는 HTTP Request에 실을 데이터인데 여러가지 타입을 넣을 수 있다.
즉, 전달하고자 하는 응답 내용이다. 백엔드와 통신할 때는 객체로 통신하기 때문에 객체타입으로 작성해야 한다.

단, JSON 데이터값을 가져와야 하기 때문에    json 문자열로 반환하기 위해 사용  

JSON.stringify({ })

 


*Content-Type 이란..
Content-Type 개체 헤더는 리소스의 media type을 나타내기 위해 사용됩니다.

응답 내에 있는 Content-Type 헤더는 클라이언트에게 반환된 컨텐츠의 컨텐츠 유형이 실제로 무엇인지를 알려줍니다. 브라우저들은 어떤 경우에는 MIME 스니핑을 해서 이 헤더의 값을 꼭 따르지는 않을 겁니다; 이를 막기 위해, X-Content-Type-Options (en-US) 헤더를  nosniff으로 설정할 수 있습니다.

요청 내에서, (POST 혹은 PUT처럼), 클라이언트는 서버에게 어떤 유형의 데이터가 실제로 전송됐는지를 알려줍니다.

 

[출처]: https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Content-Type


2.  DELETE  삭제할 때, 데이터 값을 삭제하는 것이기 때문에 window.confirm( ) 메소드를 사용하여 메시지를 지정할 수 있는 모달 대화 상자를 띄었다. 

method: ' DELETE ' 를 해줬고, 

 function del(){
        if(window.confirm('삭제하시겠습니까?')){
            fetch(`http://localhost:3001/words/${word.id}`,{
                method:'DELETE',
            }).then(res=>{
                if(res.ok){
                    setWord({id:0});
                }
            });
        }
    }

    if(word.id === 0) {
        return 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>
      );
    }

id 값 0 으로 주고 id 가 0 이면 null 값을 반환해서 바로 단어리스트에서 사라지도록 조건을 걸어주었고, 

button태그에 onClick={del} 을 해줌,.

 

3. Header.jsx 파일과 CreateWord, CreateDay 파일을 새로 생성해 그 생성된 곳에 단어를 추가할 form 을 작성해주고, Day도 추가한다. 

 

import { Link } from "react-router-dom";
export default function Header(){
    return(
        <div className="header">
            <h1 style={{textAlign:"center",}}>
                <Link to="/" style={{color:"#fff",margin:"0 auto",}}>토익 영단어(고급)</Link>    
            </h1>
            <div className="menu">
                <Link to="/create_word" className="link">단어 추가</Link>
                <Link to="/create_day" className="link">Day 추가</Link>
            </div>
        </div>
    );
}

4.  CREATE    CreateWord / CreateDay jsx 파일

 

여기서 사용할 것은 useHistory( ) / useRef( ) 라는 리액트 라우터 API 기능이다. 

 

*useRef 

JavaScript 를 사용 할 때에는, 우리가 특정 DOM 을 선택해야 하는 상황에 getElementById, querySelector 같은 DOM Selector 함수를 사용해서 DOM 을 선택합니다. 함수형 컴포넌트에서 ref 를 사용 할 때에는 useRef 라는 Hook 함수를 사용합니다. useRef() 를 사용하여 Ref 객체를 만들고, 이 객체를 우리가 선택하고 싶은 DOM 에 ref 값으로 설정해주어야 합니다. 그러면, Ref 객체의 .current 값은 우리가 원하는 DOM 을 가르키게 됩니다.
(출처: https://react.vlpt.us/basic/10-useRef.html) 

 

*useHistory( ) 

useHistory hook은 화면이동에 사용할 수 있는 history 인스턴스에 접근하게 해준다.

history 객체입니다.

리액트 라우터에서 화면이동을 할 때 항상 history, location, match 라는 객체에 필요한 정보들을 보내게 되어있습니다.

즉, 공식문서에서 말하는 history 인스턴스는 화면이동을 할 때 보내는 history, location, match 중 history에 해당합니다. 여기에 접근하게 해준다는 거죠.

-history 객체

history 객체는 라우트로 사용된 컴포넌트에게 match, location 과 함께 전달되는 props 중 하나입니다. 이 객체를 통하여, 우리가 컴포넌트 내에 구현하는 메소드에서 라우터에 직접 접근을 할 수 있습니다 - 뒤로가기, 특정 경로로 이동, 이탈 방지 등..

(출처:https://react.vlpt.us/react-router/04-extra.html)

 

CreateWord.js 코드

더보기
import {useRef} from "react";
import { useHistory } from "react-router";
import useFetch from "../hooks/useFetch";
export default function CreateWord(){
    const days = useFetch("http://localhost:3001/days");
    const history = useHistory();
    function onSubmit(e){
        e.preventDefault();


        fetch(`http://localhost:3001/words/`,{//요청의 옵션들 입력
            method:'POST',
            headers:{//Content-Type 은 보내는 리소스의 타입을 의미
                'Content-Type' : 'application/json',
        },
            body :JSON.stringify({//json 문자열로 반환하기 위해 사용
                day : dayRef.current.value,
                eng : engRef.current.value,
                kor : korRef.current.value,
                isDone : false
        }),
        }).then( res => { //응답 OK 이면 state 를 if 조건문
            if(res.ok){
                alert('생성이 완료되었습니다.');
                history.push(`/day/${dayRef.current.value}`)
            }
        });
    }

    const engRef = useRef(null) //scroll위치나 DOM 의 접근 이용할때 사용할 것> useRef
    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 =>(
                  <option key={day.id} value={day.day}>
                      {day.day}
                  </option>
              ))}
            </select>
       </div>
       <button>저장</button> 
       {/* DOM 의 결과가 렌더링 반영된 후 저장 버튼 눌려져야함. */}
    </form>
    );
}

isDone(true/false (외웠는지 안외웠는지 체크하도록)), 영단어, 한글 뜻, 날짜 선택 가능한  value 값들을 가져온다. 

 

CreateDay.js 파일

 

더보기
// import {useRef} from "react";
import { useHistory } from "react-router";
import useFetch from "../hooks/useFetch";

export default function CreateDay(){
    const days = useFetch('http://localhost:3001/days');
    const history = useHistory();
    function addDay(){
        fetch(`http://localhost:3001/days/`,{//요청의 옵션들 입력
            method:'POST',
            headers:{//Content-Type 은 보내는 리소스의 타입을 의미
                'Content-Type' : 'application/json',
            },
                body :JSON.stringify({//json 문자열로 반환하기 위해 사용
                    day : days.length + 1
            }),
        }).then( res => { //응답 OK 이면 state 를 if 조건문
            if(res.ok){
                alert('생성이 완료되었습니다.');
                history.push(`/`)
            }
        });
    }

    return(
    <div>
        <h3>현재 일수 : {days.length}일</h3>  
        <button onClick={addDay}>Day 추가</button>      
    </div>
    );
}

history.push('/') >> 메인페이지로 돌아가는 것. 혹은 그 fetch된 페이지의 날짜 리스트를 보여준다.

 

페이지에서 실행되는 영상