[DAY 19] VanillaJS를 통한 자바스크립트 기본 역량 강화 I (8)

송히·2023년 10월 16일
post-thumbnail

Today I Learn📖

  • To do App 만들기 (강의)

API 사용법

To do App에서 사용되는 API를 통해 API 기초 사용법 확인하기 !

  • todo 데이터 형태
    {
      "_id": 할 일의 고유값. 숫자와 문자가 섞여있는 문자로 되어있음,
      "content": 할 일 text,
      "isCompleted": 할 일의 완료여부
    }
  • 유저 목록 불러오기
    => API Url: https://todo-api.co.kr/users
    fetch('https://todo-api.co.kr/users').then()...
  • 할 일 목록 불러오기 (username에는 조회할 사람의 이름을 넣으면 됨)
    => API Url: https://todo-api.co.kr/:username
    fetch('https://todo-api.co.kr/songhee').then()...
  • 할 일 추가하기
    => API Url: https://todo-api.co.kr/:username
    /* 
     * 할 일 추가하는 함수의 파라미터가 (url, options = {})임. 
     * 이때 = {} 이건 따로 안 적으면 {} 을 기본값으로 갖겠다는 것
     */
    fetch('https://todo-api.co.kr/songhee', {
      method: 'POST', // POST 는 보내는 것
      headers: {
        'Content-Type': 'application/json' // 보내는 타입이 application/json라고 알리는 것, 보통 JSON 형태지만 다른 타입일 수도 있음(백엔드와 협의 후 결정하는 거니까..)
      },
      body: JSON.stringify({ // 서버로 body에다가 JSON 타입으로 보내겠다는 것
        content: '자바스크립트 공부하기'
      })
    }).then(function(){
    ...
    })
  • 할 일 삭제하기 (서버에서 불러온 개인의 각각 todo에는 고유의 id 존재, todo_id_id값 넣으면 됨)
    => API Url: https://todo-api.co.kr/:username/:todo_id
    fetch('https://todo-api.co.kr/songhee/1a2s3d4f5g6', {
      method: 'DELETE'
    }).then(function(){
      ...
    })
  • 할 일 완료 여부 토글 (todo_id에 해당하는 todo의 완료 상태 토글)
    => API Url: https://todo-api.co.kr/:username/:todo_id/toggle
    fetch('https://todo-api.co.kr/songhee/1a2s3d4f5g6/toggle', {
    	method: 'PUT'
    }).then(function(){


이벤트 델리게이션 (Event Delegation)

  • 내용이 렌더링 된 후, querySelectorAll("li"),forEach()로 모든 요소에 개별적으로 이벤트를 걸어도 됨
    -> 이 방식은 렌더링 할 때마다 새로 이벤트를 걸기 때문에, 똑같은 이벤트가 id만 다르게 계속 걸리는 것, 만약 li가 동적으로 추가된 경우에는 id가 달라지지 않아 이벤트가 걸리지 않을 것
    => 대신 이벤트 버블링 이용하기

  • 이벤트 델리게이션 (Event Delegation): 부모 요소에 하나의 이벤트만 걸고, 하위에서 생긴 이벤트들을 이벤트 버블링으로 감지해서 처리하는 것
    -> 이벤트리스너로 컴포넌트 자체에 이벤트 걸기 (click, submit, ...)
    -> 상위에 이벤트를 걸어뒀으니까, 하위에서 이벤트가 발생하면 시작한 곳부터 상위까지 계속 타고 올라가며 범인 찾음
    -> 올라가다가 실제 이벤트를 발생시킨 곳을 발견하면 원하는 애가 맞는지 확인 후, 거기서 이벤트 작동

    this.render = () => {
      $todo.innerHTML = `
        <ul>
          ${this.state.map(({ _id, content, isCompleted }) => `
            <li data-id="${_id}" class="todo-item">
              ${isCompleted ? '<s>${content}</s>' : content} 			  <button class="remove"> x </button>
            </li>
          `).join('')}
        </ul>
      `
    }
    
    $todo.addEventListener('click', (e) => {
      const $li = e.target.closest('.todo-item') // closet을 통해 이벤트 발생한 곳에서 가장 가까운 class = todo-item 찾기
    
      if ($li) { // 이벤트 발생한 곳 근처에 $li 있으면
        const { id } = $li.dataset // 그 li에 있는 data-중 뒤가 id 인 것 가져오기
        const { className } = e.target // 실제 이벤트를 발생시킨 곳(e.target)의 className 찾는 방법
        if (className === 'remove') {
          onRemove(id)
        } else {
          onToggle(id)
        }
      }
    })
    
    this.render ()
    

=> 리액트 등의 라이브러리는 내부 시스템으로 구현되어 있어서 이걸 직접 구현할 일이 없지만, 알고 있으면 좋은 개념 🥰



  • App.js에서 외부 컴포넌트를 import 해올 때

    1. new 컴포넌트처럼 객체로만 생성하는 경우:
      단발성으로, 생성과 동시에 동작하기 끝이기 때문에 값을 저장할 필요 없음

    2. const 컴포넌트명 = new 컴포넌트처럼 변수로 생성하는 경우:
      처음 렌더링된 후, 이 객체의 상태 등을 업데이트 하거나 메서드(이벤트)를 호출할 수 있기 때문


낙관적 업데이트

서버에 요청 보낸 게 100% 성공할 거라고 낙관적으로 생각하며, 서버에 요청하자마자 화면에도 요청한 값을 그려버리는 것
-> 서버에 요청하자마자 그 값으로 state를 업데이트 시키기
=> 서버에서 요청을 처리하는 게 오래걸려도, 사용자 입장에서는 바로 반영된 것 처럼 보이기 때문에 만족도 올라감

ex) 페이스북, ...


storage를 이용한 입력값 저장

로컬 스토리지의 setItem(key, value), getItem(key, defaultValue), removeItem(key)를 사용해 Form의 input에서 입력 중인 입력값을 저장할 수 있음
-> 새로고침 해도 안 날아감

const $input = $form.querySelector('input')
$input.value = getItem(TODO_TEMP_SAVE_KEY, '')

$input.addEventListener('keyup', (e) => { // keyup으로 쓰면 키보드 눌렸다가 올라올 때마다 글자가 저장됨
  setItem(TODO_TEMP_SAVE_KEY, e.target.value)
})

url에서 쿼리스트링 파싱하기

  • location.pathname: url의 도메인 뒤에 위치한 경로 반환, 쿼리 문자열이나 해시 제외
    ex) https://example.com/products/item?id=123&category=books
    ⠀⠀⠀=> /products/item

  • location.search: url의 쿼리스트링 반환
    -> 쿼리스트링은 ?으로 시작함, key=value 형태로 저장되어있음
    ex) https://example.com/products/item?id=123&category=books
    ⠀⠀⠀=> ?id=123&category=books

/* 쿼리스트링은 ?name=songhee&position=front-end 형태니까
 * &로 쪼갠 뒤, key=value의 조합을 object 형태로 만들고
 * 그 형태 리턴하기
 */
  
// querystring.js
export const parse = (querystring) => {
  querystring.split('&').reduce((acc, keyAndValue) => {
    const [key, value] = keyAndValue.split('=')

    if (key && value) acc[key] = value
    return acc
  }, {})
}
  
// App.js
import { parse } from "./querystring.js"
  
const { search } = location; // url에 특정 사용자를 나타내는 값이 있을 경우
  
if (search.length > 0) {
  const { selectedUsername } = parse(search.substring(1))
  
  if (selectedUsername) {
	this.setState({
	  ...this.state,
	  selectedUsername
	})
	await fetchTodos()
  }
}


😊오늘의 느낀점😊

오늘은 여러 명이 사용하는 To do App 실습 강의였다.
실습 강의를 통해 컴포넌트 구조, api.js 세팅, storage.js 세팅 등을 복습할 수 있었다.
이벤트 델리게이션이라는 개념이 등장해서 찾아보다가 이벤트 버블링에 대해서도 공부했고, 낙관적 업데이트에 대해서도 알게되었다.
사용자 중심의 UI 구현에 대해 알아보고, 그걸 구현하는 과정까지 보면서 프론트엔드 개발자가 중요하게 생각해야하는 게 뭔지 고민해볼 수 있었다.
저번 시간에 배운 히스토리를 붙여서 url 바꾸는 것도 다시 복습돼서 좋았다.

그리고 로토 강사님 목소리 뒤로 깔리는 고냥이 소리.,, 대박 귀여워서 힐링됏다 !♥️

profile
데브코스 프론트엔드 5기

0개의 댓글