✨ web front 데이터 요청 (2)

Kim-yujin·2023년 7월 25일

React

목록 보기
3/7
post-thumbnail

✨프론트에서 서버의 데이터 요청하기

React

💻 React 웹 프론트에서 express 서버에 데이터 요청하기

step 3. React에서 Server에 데이터 요청하기

React에서 서버로 데이터를 요청하는 방법
  • fetch사용 : 기본 제공하는 api로, 설치할 것 없이 간편하게 사용
  • axios 사용 : 리액트에서 제공하는 라이브러리로, npm i axios해야 함.
Server에 데이터 요청할 시 알아야 할 것
  • 서버 주소
  • 어떤 HTTP 메소드를 사용할 것인가 ? (DATA Method: GET, POST, HTTP......)

fetch를 활용한 데이터 요청

step 1. 서버로 데이터 요청
fetch('서버 주소/요청주소')
//첫번째 응답값은 json 형태로 정제를 해줘야 한다.  
.then((response) => response.json())
// 그러고 난 후 나오는 응답이 진짜 데이터이다. 
.then((data) => console.log(data));
step 2. CORS 정책 에러 발생

CORS 정책이란 ?
1. cross origin resource sharing의 약자
2. 교차 출처 리소스 공유
3. 다른 출처의 리소스 공유에 대한 허용/비허용 정책
4. CORS는 SOP 정책을 위반해도 CORS 정책에 따르면 다른 출처의 리소스라도 허용
CORS 정책이 발생하는 이유
-> 웹 브라우저에서 HTTP 요청에 대해서 어떤 요청을 하느냐에 따라 각기 다른 특징을 가지고 있기 때문.
-> 자바스크립트에서의 요청은 "기본적으로 서로 다른 도메인에 대한 요청을 보안상 제한"하기 때문.

정리

클라이언트 실행 출처(localhost:3000)와 서버 실행 출처(localhost:4000)의 origin이 다르기 때문에 CRUD 에러를 발생시키고, 이를 해결하기 위해서는 서버에서 CRUD 정책을 허용해서 origin이 달라도 클라이언트에서 접근할 수 있도록 할 수 있다.

//server 코드
터미널 > npm i cors
const cors = require('cors')
app.use(cors())
// 요청 본문에 있는 JSON 데이터 파싱, 클라이언트가 JSON 데이터를 전송한 경우 사용. ex) req.body
app.use(express.json()); 
// 폼 데이터를 파싱하는데 사용 queryString이나, form 데이터 형식으로 파싱할 수 있도록 허용 
app.use(express.urlencoded{ { extended: true }}); 

step 3. 서버의 데이터 클라이언트에서 출력
01. useState

useState를 활용하여 서버에서 응답이 오면 상태가 변경되도록 하기
!! useState는 값이 변경되면 리렌더링이 된다.!!
!! 다시 변경된 값을 가지고 실행됨을 의미 !!

const [datalist, setDataList] = useState(null);
....
fetch('서버주소/요청주소')
.then((response) => response.json())
.then((data) => setDataList(data))
그러나 useState를 잘못 사용할 시, 무한 반복에 빠져서 계속 상태 변화를 감지에 리렌더링을 반복하게 된다. 이를 해결하기 위해서 useEffect를 사용한다.
02. useEffect

useState의 리렌더링을 조절하고 싶을 떄, useEffect를 사용한다.


처음 한번만 리렌더링 되도록하기

useEffect ( () => {
	fetch('서버주소/요청주소')
    .then((response) => response.json())
    .then((data) => setDataList(data));
//useEffect의 두 번쨰 인자로 dependancy에 아무것도 넣지 않으면 한 번에 렌더링이 된다
}, []);

03. 출력하기

JSX 파일의 return문 안에서 출력
데이터 값이 하나가 아닌 객체나 배열일 시에는 map 사용 권장

<div>
	<h1> DATA </h1>
    <!-- map을 활용하여 배열을 순차적으로 순회시킴 -->
    {todoList.map( (todo) => (
    	<div key={todo.id}>
        	<div>{todo.id}</div>
        	<div>{todo.data1}</div>
            <div>{todo.data2}</div>
        </div>
     ))}
</div>

만약 데이터를 요청하기 전에 null 값이 todoList에 들어오면 null.map이 되어 에러가 발생하므로 todoList에 null 값이 들어오간, todo가 없을 때는 optional chaining으로 undefined를 만들어 렌더링이 되지 않도록 함.

<div>
	<h1> DATA </h1>
    <!-- todoList? 사용  -->
    {todoList?.map( (todo) => (
    	<div key={todo.id}>
        	<div>{todo.id}</div>
        	<div>{todo.data1}</div>
            <div>{todo.data2}</div>
        </div>
     ))}
</div>
04. 데이터 삽입 요청
  1. 화면에 데이터 입력/삽입 할 수 있는 화면 구현하기
<!-- 데이터를 입력하고 추가 버튼 클릭 시 form의 onSubmin을 이용해 원하는 값을 받아서 데이터를 보낼 수 있음 -->
<form onSubmit={}>
	<input name='text'/>
    <input name='done' type='checkbox'/>
    <input name='submit' value='데이터추가'/>
</form>
  1. onSubmit 함수를 작성해서 추가 버튼 클릭 시 서버에 데이터 추가를 요청하는 함수 구현
const onSubmitHandler = (e) => {
	const text = e.target.text.value;
    //check박스이기 때문에 checked로 T/F 체크함. 
    const done = e.target.done.checked;
    // 데이터를 {}에 담아서 보내준다. 
    fetch('http//localhost:4000/insert', {
    	// 아무것도 적지 않으면 GET 요청이지만 
        // 삽입요청을 해야 하기 때문에 POST 요청을 보냄. 
    	method: 'POST',
        // header에 콘텐츠타입을 넣어줘야 한다. 
        // 내가 지금 보낸 데이터가 JSON 데이터라는 걸 알려줘야 바이에서 파싱할 때 json 형태로 파싱해서 어디에 쓸 수 있기 때문이다. 
        headers: {
        	'Content-Type': 'application/json',
       	},
        // 데이터를 넣어줄 때는 front에서 body에 담아서 보내주기 때문에 body 라는 곳에다가 문자열로 직렬화를 해서 보내준다.
        // 직렬화(JSON.stringify)는 원래의 형태를 JSON 형태로 변환하는 것 
    	body: JSON.stringify({
    		text,
        	done,
    	}),
	});
};
  1. submit을 클릭해서 서버에 요청(data1=test&data2=test2)을 보낸 후, 다시 submit을 작성할려고 하면, 해당 클라이언트 주소에 전에 보낸 요청값이 기본 동작(localhost:3000/?data1=test&data2=test2)이 유지되는 문제 해결
const onSubmitHandler = (e) => {
	// 기본 동작 유지 변경하기  
    e.preventDefault();
    ...
}
  1. 데이터 추가 될 떄마다 바로바로 변경된 데이터를 받아오도록 onSubmitHandler 함수 수정하기
const onSubmitHandler = (e) => {
	const text = e.target.text.value;
    const done = e.target.done.checked;
    fetch('http//localhost:4000/insert', {
    	method: 'POST',
        headers: {
        	'Content-Type': 'application/json',
       	},
    	body: JSON.stringify({
    		text,
        	done,
    	}),
    //클릭이 끝난 후, 변경된 데이터를 다시 가져오도록 
    //fetch에서 요청이 끝났을 때. (.then)다시 되도록 
	}).then(() => 
    	fetch('서버주소/요청주소')
        .then((response) => response.json())
        .then((data) => setDataList(data))
      )
};
  1. 문제 발생! 동일한 코드 중복 사용하는 구간이 발생함, 중복 발생되는 코드를 함수로 빼서 코드 수정하기
fetch('서버주소/요청주소')
        .then((response) => response.json())
        .then((data) => setDataList(data))

수정된 코드

const fetchData = () => {
	fetch('서버주소/요청주소')
        .then((response) => response.json())
        .then((data) => setDataList(data))
}

기존에 실행되는 곳에서는 함수를 실행시켜주면 된다.

useEffect{ () => {fetchData()}, []);
...
const onSubmitHandler = (e) => {
	.....
 	}).then( () => fetchData() );
}

클라이언트 전체 코드 (fetch 활용)

import React, {useState, useEffect} from 'react';

const App = () => {
	// 데이터를 담을 useState 값 
	const [datalist, setDataList] = useState(null);
    // 데이터를 가져오는 fetchData 함수 
    const fetchData = () => {
        fetch('서버주소/요청주소')
            .then((response) => response.json())
            .then((data) => setDataList(data))
    }
    // 젤 처음 실행 시 렌더링 되도록 하는 useEffect
    // useEffect의 두 번쨰 인자로 dependancy에 아무것도 넣지 않으면 한 번에 렌더링이 된다
    useEffect{ () => {fetchData()}, []);
    const onSubmitHandler = (e) => {
    	// 기본 동작 유지 변경하기  
    	e.preventDefault();
		const text = e.target.text.value;
        const done = e.target.done.checked; //check박스이기 때문에 checked로 T/F 체크함. 
        // 데이터를 {}에 담아서 보내준다. 
        fetch('http//localhost:4000/insert', {
            // 아무것도 적지 않으면 GET 요청이지만,삽입요청을 해야 하기 때문에 POST 요청을 보냄. 
            method: 'POST',
            // header에 콘텐츠타입을 넣어줘야 한다. 
            // 내가 지금 보낸 데이터가 JSON 데이터라는 걸 알려줘야 바이에서 파싱할 때 json 형태로 파싱해서 어디에 쓸 수 있기 때문이다. 
            headers: {
                'Content-Type': 'application/json',
            },
            // 데이터를 넣어줄 때는 front에서 body에 담아서 보내주기 때문에 body라는 곳에다가 문자열로 직렬화를 해서 보내준다.
            // 직렬화(JSON.stringify)는 원래의 형태를 JSON 형태로 변환하는 것
          body: JSON.stringify({
              text,
              done,
          }),
      //클릭이 끝난 후, 변경된 데이터를 다시 가져오도록 
      //fetch에서 요청이 끝났을 때. (.then)다시 되도록 
      }).then( () => fetchData() );
    }
  return (
  	<div>
      <h1> DATA </h1>
      <!-- 데이터를 입력하고 추가 버튼 클릭 시 form의 onSubmin을 이용해 원하는 값을 받아서 데이터를 보낼 수 있음 -->
      <form onSubmit={onSubmitHandler}>
          <input name='text'/>
          <input name='done' type='checkbox'/>
          <input name='submit' value='데이터추가'/>
      </form>
      <!-- todoList? 사용  -->
      {todoList?.map( (todo) => (
          <div key={todo.id}>
              <div>{todo.id}</div>
              <div>{todo.data1}</div>
              <div>{todo.data2}</div>
          </div>
       ))}
  </div>
  )
}
export default App;
profile
🐰노력하며 살아가기🐰

1개의 댓글

comment-user-thumbnail
2023년 7월 25일

좋은 정보 감사합니다

답글 달기