connecting dots

Beginner 5회차 2 (7/30) | fetch문에서 옵션 넣기, 캡슐화, React 라이브러리를 import하는 경우와 그렇지 않은 경우, 이벤트 객체 본문

Live Class/Beginner

Beginner 5회차 2 (7/30) | fetch문에서 옵션 넣기, 캡슐화, React 라이브러리를 import하는 경우와 그렇지 않은 경우, 이벤트 객체

dearsuhyun 2024. 7. 30. 20:02

fetch 함수에서 옵션 넣기

async function getTodos() {
    try {
      // await new Promise(resolve => setTimeout(resolve, 2000))
      const res = await fetch(
        'https://~~~~',
        {
          headers: {
            'content-type': 'application/json',
            apikey: '~~~',
            username: '~~~'
          }
        }
        
// 수강생 전용 정보는 '~~~'로 처리함

 

fetch('주소', {
  headers: {},
  body: {}.
  method: 'GET'
})

 

위와 같이 fetch문을 사용할 때 주소 이외에도 옵션 넣기 가능 --> 요청의 설정 객체

요청 설정(options) 객체

1. headers 객체(서버에 보낼 추가 정보)
headers는 요청에 포함될 HTTP 헤더를 지정합니다.
HTTP 헤더는 클라이언트와 서버 간에 전송되는 부가 정보를 포함합니다. 예를 들어, 콘텐츠 타입, 인증 정보 등을 설정할 수 있습니다.
headers: {
  'Content-Type': 'application/json',
  'Authorization': 'Bearer your-token'
}​

• Content-Type: 서버에 보내는 데이터의 MIME 타입을 지정합니다. 예를 들어, JSON 데이터를 전송할 때는 'application/json'을 사용합니다.
• Authorization: 인증 토큰 등을 포함하여 요청이 인증된 사용자인지를 서버에 알릴 수 있습니다.

2. body 객체 (서버에 보낼 데이터)
body는 요청의 본문을 지정합니다. GET 및 HEAD 요청에서는 사용되지 않습니다.
주로 POST, PUT, PATCH 요청에서 데이터를 전송할 때 사용됩니다.
body: JSON.stringify({
  key1: 'value1',
  key2: 'value2'
})​

• JSON.stringify: JavaScript 객체를 JSON 문자열로 변환합니다. 이는 서버가 데이터를 올바르게 해석할 수 있도록 합니다.

3. method 속성
method는 HTTP 요청 메서드를 지정합니다. 기본값은 'GET'입니다. 요청 메서드는 서버에서 수행할 작업을 나타냅니다.
method: 'GET' // GET, POST, PUT, DELETE 등​

• GET: 데이터를 요청합니다. (body는 사용되지 않습니다)
• POST: 서버에 데이터를 보냅니다.
• PUT: 서버의 데이터를 업데이트합니다.
• DELETE: 서버의 데이터를 삭제합니다.

4. 예제
fetch('주소', {
  headers: {
    'Content-Type': 'application/json'
  },
  method: 'GET'
})
.then(response => response.json()) // 서버의 응답을 JSON 형식으로 변환
.then(data => console.log(data)) // 변환된 데이터를 콘솔에 출력
.catch(error => console.error('Error:', error)); // 요청이 실패했을 때 오류를 처리​

 

캡슐화

기존 코드

;<li key={user.title}>
  {user.title}
  <input {/* type="text"는 input의 기본값이라 생략가능 */}
    value={title}
    onChange={}
  />
</li>

 

반복되는 코드는 함수로 분리하는 것이 좋음

--> 반복되는 코드인데 name이라는 단일 데이터를 넣어주는 것은 말이 안됨 (각 영역은 독립적인 부분인데 이름 데이터는 1개인 상황)

분리하는 가장 대표적인 방법 = 컴포넌트화 !

 

import { useState, useEffect, Fragment } from 'react'
// import React, { useState, useEffect } from 'react' --> 밑에 <React.Fragment>라고 써야 됨

export type Todos = Todo[]
export interface Todo {
  id: string
  order: number
  title: string
  done: boolean
  createdAt: string
  updatedAt: string
}

return (
    <>
      <div>{loading && <TheLoader />}</div>
      <div>{message}</div>
      <ul>
        {todos.map(todo => (
        // 리액트를 클래스(데이터)로 사용할 때는 import 필요
          <Fragment key={todo.id}>
            <TodoItem abc={todo} />
          </Fragment>
        ))}
      </ul>
    </>
  )

 

TodoItem.tsx 파일을 만들어서 반복되는 부분을 컴포넌트 화하고 이를 import해서 가져다 쓰는 방식

key={todo.id} --> 키 값을 todo.id로 주어서 각 부분이 구분되도록 !

<> = <React.Fragment>

 

TodoItem.tsx

import { useState } from 'react'
import type { Todo } from '../App' // type으로 가지고 올거야 명시(중요)

export default function UserItem({ abc }): { abc: Todo } {
  const [title, setTItle] = useState(abc.title) // 하나의 데이터와 하나의 인풋을 연결

  // 타입으로 사용하는 리액트는 import 안 해도 됨
  function keydownHandler(event: React.KeyboardEvent<HTMLInputElement>) {
    if (event.key === 'Enter') {
      console.log('서버로 전송', title)
      // await 서버로 전송(수정할 이름)
    }
  }

  return (
    <li>
      {abc.title}
      <input
        value={title}
        onChange={e => setTItle(e.target.value)}
        onKeyDown={keydownHandler} // 키를 눌렀을 때 핸들러
      />
    </li>
  )
}

 

코드 설명

1. 필요한 모듈 import

 useState: 리액트에서 상태를 관리하기 위해 사용하는 훅(Hook)

 Todo: ../App에서 정의된 Todo 타입을 임포트. 타입은 컴파일러가 타입 검사를 할 수 있도록 도와줌

import { useState } from 'react'
import type { Todo } from '../App'

 

2. 컴포넌트 정의

UserItem: 이 컴포넌트는 abc라는 prop을 받음. abc의 타입은 Todo로 지정

export default function UserItem({ abc }): { abc: Todo } {

 

타입이란?

타입은 데이터의 형태와 구조를 정의합니다. JavaScript는 동적 타입 언어라서 변수가 어떤 타입의 값을 가질 수 있는지 명시적으로 알 수 없습니다. 그러나 TypeScript는 정적 타입 언어로, 타입을 명시하여 변수가 어떤 타입의 값을 가질 수 있는지 정의할 수 있습니다.

Todo 타입 정리
export interface Todo {
  id: string;
  order: number;
  title: string;
  done: boolean;
  createdAt: string;
  updatedAt: string;
}​


Todo 타입 사용 예제

import type { Todo } from './path-to-todo-type';

function printTodoDetails(todo: Todo) {
  console.log(`ID: ${todo.id}`);
  console.log(`Title: ${todo.title}`);
  console.log(`Completed: ${todo.done}`);
}​


타입 정의를 사용하는 것이 중요한 이유

가독성 향상: 타입 임포트를 명시적으로 하면, 코드 가독성이 높아집니다.

명확한 의도 전달: type 키워드를 사용하여 타입임을 명확히 합니다.

트리 쉐이킹 지원: 불필요한 코드가 번들링되지 않도록 돕습니다.

타입스크립트는 import type을 사용하여 타입을 임포트할 때, 실제 번들링 시 불필요한 코드가 포함되지 않도록 도와줍니다. 이는 트리 쉐이킹(tree shaking)을 지원하여 번들 크기를 줄이는 데 도움이 됩니다.

코드 정리와 구분: 실제 코드와 타입 정의를 명확히 구분할 수 있습니다.

 

 

3. 상태 선언 및 초기화

useState 훅을 사용하여 title이라는 상태를 선언하고 초기값으로 abc.title을 설정함.

setTItle 함수는 title 상태를 업데이트하는 데 사용됨

const [title, setTItle] = useState(abc.title);

 

4. 키보드 이벤트 핸들러

keydownHandler: input 요소에서 키를 눌렀을 때 실행되는 함수

event.key === 'Enter': 엔터 키를 눌렀을 때 실행된다는 의미

• event: React.KeyboardEvent<HTMLInputElement> 

이벤트가 발생하는 요소의 타입이 input 요소임을 명시적으로 지정해주는 것

console.log('서버로 전송', title): 콘솔에 “서버로 전송”과 현재 title 값을 출력

// await 서버로 전송(수정할 이름): 서버로 수정된 이름을 전송하는 코드가 들어갈 곳

function keydownHandler(event: React.KeyboardEvent<HTMLInputElement>) {
  if (event.key === 'Enter') {
    console.log('서버로 전송', title);
    // await 서버로 전송(수정할 이름)
  }
}

 

event: React.KeyboardEvent<HTMLInputElement> 

이벤트가 발생하는 요소의 타입이 input 요소임을 명시적으로 지정해주는 것

 

event: 이벤트 객체로, 이벤트에 대한 정보를 포함합니다.

React.KeyboardEvent: 키보드 이벤트 객체를 나타내는 React 타입입니다.

<HTMLInputElement>: 이벤트가 발생한 요소의 타입을 나타냅니다. 여기서는 <input> 요소를 의미합니다.

 

Q&A

Q. 'keydown 이벤트가 발생하는 요소의 타입이 input임을 명시적으로 지정해주는 역할'로 이해하면 될까요 
A. 네 맞습니다!다른 요소에서도 keydown 이벤트는 발생할 수 있는데, 그렇게 요소가 달라지면 이벤트 객체(event)에서 사용할 수 있는 명령도 일부 달라질 수 있어서 인풋 요소라는 것을 명확히 하는 부분입니다.

Q. 이 부분을 사용하는 것이 필수인지도 궁금합니다
A. 네 '리액트+타입스크립트'를 사용할 때의 이벤트 객체의 정확한 타이핑은 필수입니다!

Q. keydown 이벤트는 input 뿐만 아니라 form에서도 사용할 수 있는 것 같은데, 이렇게 input과 form을 같이 사용할 때는 input과 form 각각에 타입을 지정해주면 되는걸까요 ?
A. 단일 keydown 이벤트 핸들러를 서로 다른 요소에서 사용한다면, 다음과 같이 유니온 타입( |)으로 지정할 수 있습니다.
HTMLInputElement일 수도 있고, HTMLFormElement 일 수도 있다는 뜻입니다.
event: React.KeyboardEvent<HTMLInputElement | HTMLFormElement>​
keydown 이벤트는 input, form 외에도 대표적으로 div요소에서도 사용할 수는 있습니다.
이럴 때는 하나씩 지정하기 어려우니, 다음과 같이 포괄적으로 지정하는 것도 가능합니다.
그냥 'HTML 요소'라는 의미입니다.
event: React.KeyboardEvent<HTMLElement>​

Q. '리액트+타입스크립트를 사용할 때, 이벤트가 발생하는 부분에는 모두 필수적으로 타입지정을 해줘야 한다 !' 라고 이해하면 될까요 ?
A. "이벤트가 발생하는 부분에서 모두 필수이다"라고 할 수는 없습니다.
간혹 추론할 수 있는 경우도 있어서 필수라고 단언할 수는 없지만, 대부분은 타입을 지정하는 게 필요합니다.

 

 

5. 컴포넌트 변환

{abc.title}: abctitle을 화면에 표시

 

value={title}

입력 필드의 현재 값을 지정, 여기서는 title 상태변수를 값으로 사용함

이 속성을 통해 입력 필드의 값이 항상 title 상태와 일치하도록 함

 

onChange={e => setTItle(e.target.value)}:

입력 필드의 값이 변경될 때마다 setTItle 함수를 호출하여 title 상태를 업데이트

onChange 속성은 입력 필드의 값이 변경될 때 실행될 함수를 지정

e는 이벤트 객체로, 입력 필드에서 발생한 이벤트에 대한 정보를 담고 있음

setTitle 함수는 title 상태를 업데이트하는 함수

 

onKeyDown={keydownHandler}: 키를 눌렀을 때 keydownHandler 함수를 호출

return (
  <li>
    {abc.title}
    <input
      value={title}
      onChange={e => setTItle(e.target.value)}
      onKeyDown={keydownHandler}
    />
  </li>
);

 

onChange 이벤트 핸들러

onChange는 HTML 요소의 속성 중 하나로, 입력 값이 변경될 때 실행되는 이벤트 핸들러입니다.

주로 input, textarea, select 요소에서 사용됩니다.


자세한 설명


1. 이벤트 객체 (e)
e는 이벤트 객체로, 입력 필드에서 발생한 이벤트에 대한 다양한 정보를 제공합니다. 여기서는 e를 통해 입력 필드의 현재 값을 가져옵니다.

2. 입력 필드의 현재 값 가져오기 (e.target.value)
e.target은 이벤트가 발생한 요소(즉, input 요소)를 가리킵니다. e.target.value는 입력 필드의 현재 값을 의미합니다.

3. 상태 업데이트 (setTitle(e.target.value))
setTitle 함수는 title 상태를 업데이트하는 함수입니다. setTitle(e.target.value)는 입력 필드의 현재 값으로 title 상태를 업데이트합니다.

전체 과정 설명

 

1. 사용자가 입력 필드에 값을 입력합니다.

2. 입력 필드의 값이 변경되면 onChange 이벤트가 발생합니다.

3. onChange 이벤트 핸들러로 지정된 함수가 실행됩니다.

4. 함수 내부에서 e.target.value를 통해 입력 필드의 현재 값을 가져옵니다.

5. setTitle 함수를 사용하여 title 상태를 입력 필드의 현재 값으로 업데이트합니다.

6. 상태가 업데이트되면, 입력 필드의 value 속성도 새 값으로 변경되어 입력 필드에 표시됩니다.

 

결과

초기값 Neo --> suhyun으로 바꾼 후 엔터 눌렀을 때 console에 출력 화면

 

React 라이브러리를 import하는 경우와 그렇지 않은 경우

1. 실제로 사용하는 경우(클래스로 사용하는 경우)

컴포넌트를 실제로 사용하여 화면에 렌더링할 때 React 라이브러리를 임포트해야 함

--> 우리가 컴포넌트를 정의하고 렌더링하기 위해 필요한 함수와 클래스들을 포함하기 때문 !

<Fragment key={todo.id}>
  <TodoItem abc={todo} />
</Fragment>
• Fragment와 TodoItem: React 컴포넌트입니다. Fragment는 여러 요소를 그룹화하는 데 사용되며, TodoItem은 할 일 아이템을 표시하는 사용자 정의 컴포넌트입니다.

• 임포트 필요: Fragment와 TodoItem을 사용하려면 React와 TodoItem 컴포넌트를 임포트해야 합니다. 이는 실제로 컴포넌트를 사용하여 화면에 렌더링하기 때문입니다.

 

2. 타입으로 사용하는 경우

타입스크립트에서 타입 검사를 위해 타입을 정의할 때 React 라이브러리를 임포트할 필요가 없음

--> 이는 컴파일 타임에만 사용되기 때문

cf. 컴파일 타임(compile time):
컴퓨터 프로그램을 작성하고 실행하는 과정에서, 소스 코드를 기계어로 번역하는 컴파일 과정이 이루어지는 시점
런타임(Runtime):프로그램이 실제로 실행되는 시점

 

function keydownHandler(event: React.KeyboardEvent<HTMLInputElement>) {
  if (event.key === 'Enter') {
    console.log('서버로 전송', title)
    // await 서버로 전송(수정할 이름)
}

 

• React.KeyboardEvent<HTMLInputElement>: 
이 부분은 이벤트 핸들러에서 타입을 사용하는 예제입니다. 여기서 React.KeyboardEvent<HTMLInputElement>는 이벤트 객체의 타입을 정의하는 데 사용됩니다. 이는 입력 필드에서 발생하는 키보드 이벤트를 의미합니다.
타입을 사용하면 TypeScript가 컴파일 타임에 타입 검사를 수행하여 코드의 타입 안전성을 보장할 수 있습니다.

• 임포트 불필요: 이 경우에는 타입만 사용하기 때문에 React를 임포트할 필요가 없습니다. 타입스크립트는 타입 정보를 컴파일 타임에만 사용하며, 실제 런타임에는 영향을 미치지 않기 때문입니다.

 

 

반응형