강의

리액트 심화 주차 필수 개념 정리(1)

choijming21 2024. 9. 6. 17:40

필수 개념은 다음과 같다.

  1. [1-2] 비동기1 - 비동기, promise
  2. [1-5] json-server
  3. [1-6 ~ 1-7] axios의 GET, POST, DELETE, PATCH, fetch와의 비교
  4. [1-10] tanstack query 기본 사용법 (매우중요)
  5. [1-15] zustand 기본 사용법
  6. [1-20] 인증인가 개념 실습
  7. [1-21] tailwind

 

 

[1-2] 비동기, promise

< 동기와 비동기 개념 >

동기: 순차적으로 진행, 요청을 보내고 응답을 기다린다.

(ex 주문 후, 커피가 나올 때까지 기다려주세요!  다음사람들은 아직 주문 못한 상태로 기다리는중...)

 

비동기: 비순차적으로 진행, 요청을 보내고 응답을 기다리지 않고 바로 다음 작업을 진행한다.

(ex 주문 후, 진동벨이 울리면 커피를 가지러 오세요! 모든 사람들의 주문을 다 받고 음료 준비가 다 된 순서대로 줌)

동기 비동기 이미지

 

Promise란?

promise는 비동기 작업의 완료 또는 실패를 처리하기 위해 사용되는 개념이다.

비동기 작업의 결과를 다루기 쉽게 하기 위해 만들어졌으며, 비동기 작업이 끝난 이후에 실행될 콜백 함수를 등록할 수 있는 메서드를 제공한다. promise 객체를 생성하기 위해 promise 생성자를 사용할 수 있다.

 

promise는 세 가지 상태를 가진다.

  • Pending(대기): 초기 상태이다. 즉, 이행되거나 거부되지 않은 상태이다. 
  • Fulfilled(이행): 비동기 작업이 성공적으로 완료된 상태이다.
  • Refected(거부): 비동기 작업이 실패한 상태이다.

promise 상태

 

promise 객체는 then, catch, finally 매서드를 통해 이행되거나 거부된 이후의 동작을 정의할 수 있다.

 

 

 

직접 promise 객체 만들기

const myPromise = new Promise((resolve, reject) => {
  // 비동기 작업을 수행합니다.
  if (/* 작업이 성공적으로 완료되면 */) {
    resolve("성공 메시지");
  } else {
    reject("실패 메시지");
  }
});

 

사용방법 포함

const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    // 작업의 성공 여부를 나타내는 변수
    // 여기를 true <-> false 변경해가며 테스트해보세요!
    const success = true;

    if (success) {
      // resolve 함수는 Promise 객체의 상태를 이행(fulfilled) 상태로 변경해요.
      // resolve 함수 자체는 반환값이 없어요.
      // 다만, resolve 함수가 호출되면 그 값이 then 메서드의 callback 함수로 전달돼요.
      resolve("작업이 성공적으로 완료되었습니다!");
    } else {
      // 마찬가지 원리로, reject 함수가 호출되면 그 값이 catch 메서드의 callback 함수로 전달돼요.
      reject("작업이 실패했습니다.");
    }
  }, 2000); // 2초 후에 작업이 완료
});

myPromise
  .then((result) => {
    console.log(result); // "작업이 성공적으로 완료되었습니다!" 출력
  })
  .catch((error) => {
    console.log(error); // "작업이 실패했습니다." 출력
  });

 

본격적으로 알아보기!

// React 라이브러리에서 useState와 useEffect 훅을 가져옵니다.
// useState는 상태 관리를 위해, 기억하죠?
// useEffect는 컴포넌트의 생명주기 동안 특정 작업을 수행하기 위해!
import React, { useState, useEffect } from "react";

function App() {
  // state 선언 및 초기화
  // setMessage : 상태 업데이트 함수
  // useState는 상태 변수와 그 변수를 업데이트하는 함수를 반환합니다.
  // 즉, 좌측의 [state, setState] 구조는 useState의 결과물을 '구조분해할당'한 것이죠!
  const [message, setMessage] = useState("타이머 시작");

  // useEffect 훅을 사용하여 컴포넌트가 마운트되었을 때 실행될 효과를 정의
  // 빈 배열 []을 두 번째 인자로 넘겨주어, 이 효과가 컴포넌트가 처음 렌더링 된 후 한 번만 실행
  useEffect(() => {
    // delay 함수 정의
    // (1) delay 함수는 Promise 객체를 새로(new) 만들어 반환합니다.
    //   ** 여기서 Promise는 객체를 생성하기 위한 생성자입니다.
    // (2) 만들어진 promise 객체는 주어진 밀리초(ms)만큼 동작을 지연시킵니다.

    // (1) delay함수는 주어진 밀리초(ms)만큼 지연시키는 Promise를 반환합니다.
    // (2) setTimeout을 사용하여 지정된 시간(ms) 후에 resolve를 호출합니다.
    // (3) 따라서, 지정된 시간(ms) 후에 pending -> fulfilled로 상태가 바뀌어요.
    const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

    // (1) delay 함수를 호출하여 2000밀리초(2초) 동안 지연시킵니다.
    // (2) delay 함수가 반환하는 Promise가 완료되면 then 메서드가 호출되고, 이 메서드 안의 콜백 함수가 실행됩니다.
    // (3) 이 콜백 함수는 setMessage를 호출하여 message 상태를 "2초 후 메시지 변경"으로 업데이트합니다.
    delay(2000).then(() => setMessage("2초 후 메시지 변경"));
  }, []);

  // 초기 상태는 "타이머 시작"이며, 2초 후에는 "2초 후 메시지 변경"으로 업데이트됩니다.
  return (
    <div>
      <h1>{message}</h1>
    </div>
  );
}

export default App;

 

 

 

다른 쉬운 예시

const fetchData = new Promise((resolve, reject) => {
  // 가상의 데이터 fetch
  setTimeout(() => {
    const data = { id: 1, name: "John" };
    resolve(data);  // 데이터와 함께 resolve 호출
  }, 1000);
});

fetchData.then(data => console.log(data));  // { id: 1, name: "John" } 출력

 

promise의 구조: promise 생성자는 실행자 함수를 인자로 받는다. 이 실행자 함수는 두개의 인자를 받는다. resolvereject

new Promise((resolve, reject) => {
  // 비동기 작업 수행
});

 

resolve의 역할

  • resolve는 promise가 성공적으로 완료 되었음을 나타내는 함수
  • resolve를 호출하면 promise의 상태가 'fullfilled(이행)'으로 변경됨.
  • resolve에 전달된 값은 promise의 결과값이 됨.

then의 역할

  • promise가 fullfilled(이행) 상태가 되면 then 에 등록된 콜백함수가 실행됨.
  • promise의 결과값을 이 콜백함수의 인자로 전달
fetchData.then(data => console.log(data));
  • data는 promise의 결과값이다.

 

 

실생활에서 사용 ⭐⭐⭐⭐⭐

useEffect(() => {
	fetch("URL")
    	.then((response) => response.json())
        .then((json) => console.log(json));
}, []);

 

  1. fetch 함수:
    • fetch("URL")는 Promise를 반환한다.
    • 이 Promise는 네트워크 요청이 완료되면 Response 객체로 이행(fulfill)된다.
  2. 첫 번째 .then():
    • response.json()은 Response 객체의 본문을 JSON으로 파싱하는 메서드이다.
    • 이 메서드도 Promise를 반환한다.
  3. 두 번째 .then():
    • 파싱된 JSON 데이터를 받아 처리한다.
    • 여기서는 단순히 콘솔에 로그를 출력한다.

이 코드의 Promise 체인을 단계별로 살펴보면:

  1. fetch("URL") Promise가 완료된다.
  2. 첫 번째 .then()이 실행되어 응답을 JSON으로 파싱한다.
  3. 두 번째 .then()이 실행되어 파싱된 JSON 데이터를 처리한다.

이 구조는 "Promise 체이닝"이라고 불립니다. 각 .then()은 이전 Promise의 결과를 받아 처리하고, 새로운 Promise를 반환한다.

 

 

 

 

 

 

 

[1-5] json-server

json-server란?

아주 간단한 DB와 API 서버를 생성해주는 패키지이다. 우리가 사용하는 이유는 백엔드에서 실제 DB와 API 서버가 구축될 때까지 프론트엔드 개발에 임시적으로 사용할 mock data를 생성하기 위함이다.

 

 

설치

yarn add json-server
yarn add json-server -D # 개발 환경인 경우, -D 옵션을 함께 입력합니다.

 

 

파일 생성

아래 이미지처럼 프로젝트 루트 경로에 db.json이라는 파일을 생성한다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

그리고 아래와 같이 내용을 입력한다. json-server는 이 내용을 바탕으로 데이터베이스를 제공하게 된다.

{
  "todos": []
}

 

 

 

내가 추가하고 싶은 내용으로 수정한다.

{
  "todos": [
    {
      "id": 1,
      "title": "json-server",
      "content": "json-server를 배워봅시다."
    }
  ]
}

 

 

 

이렇게 작성했으면 내가 만든 API 서버가 잘 작동하고 있는지 확인해야한다.

먼저, 터미널에 아래의 코드를 입력한다. 이렇게 하면 4000번 포트에서 돌아가는 서버가 실행된다.

yarn json-server db.json --port 4000

 

그리고 브라우저에 http://localhost:4000/todos를 입력한다. 그러면 잘 작동하고 있는 것을 볼 수 있다.

 

'강의' 카테고리의 다른 글

리액트 심화 주차 필수 개념 정리(2)  (1) 2024.09.06