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

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

Today I Learn📖

  • 컴포넌트 방식의 사고, TodoList 만들기 (강의)
  • Client Side 데이터 저장 (Cookie, Local & Session Storage) (강의)

npx serve로 로컬 서버 실행 가능

컴포넌트 방식으로 생각하기

  • 컴포넌트: 비슷한 역할끼리 하나로 묶어 분리하는 것
    -> 재사용성, 유지보수 용이성, 독립성이 높음 (수정해도 다른 컴포넌트에 영향을 주지 않음)


예시: 투두리스트의 UI를 선언적으로 표현한 추상화
(컴포넌트들은 모두 각각 하나의 독립적인 단위)
App
ㄴ Header
ㄴ main
ㄴ TodoForm
ㄴ TodoList

강사님 개인적인 컨벤션 (이자 Tip) !

  • $변수명: DOM 객체를 담고 있는 변수 ( or 변수명+Element)

프로젝트 실행 방법
1. node.js 설치
2. 터미널에서 npx serve 실행
3. 해당 로컬 호스트 실행~
(만약 오류 나면 npx serve -l (원하는 포트번호))


TodoList 컴포넌트

TodoList 컴포넌트를 그리기 위한 기본 세팅은 다음 코드와 같다.
(할 일 목록 나열)

// params가 가져야 할 초기 상태 2가지
// params.$target - 해당 컴포넌트가 추가될 DOM 엘리먼트
// params.initioalState - 해당 컴포넌트의 초기 상태 (text 등)

function TodoList(params) {
  const $todoList = document.createElement("div"); // TodoList 컴포넌트의 DOM
  const $target = params.$target; // TodoList를 그릴 대상 DOM
  $target.appendChild($todoList);

  this.state = params.initialState;

   // 위에서 컴포넌트 생성, 할당시키는 과정임

  this.render = () => {
  /* 넘겨받은 상태를 가지고 화면에 그림 (그린 상태로 저장, 보여주진 않음) */ 
  };
    
  this.render(); // 바로 렌더링 실행 시켜서 화면에 보여줌
}

하나의 컴포넌트를 작성하기 전에 해당 컴포넌트가 어디에 그려질 것인지, 어느 것의 자식 요소로 들어갈 것인지, 가지고 있어야 할 속성(초기 상태)는 무엇인지를 생각해야한다.

객체의 특정 속성을 바로 매개변수로 받기

위 코드에서 params 객체의 특정 속성($target, initialState)만 바로 꺼내서 사용할 수 있음
=> 매개변수 params 자리에 그 객체에서 꺼내오고 싶은 특정 속성만 {}로 감싸서 적기
-> 밑에 작성하게 될 코드에서도 params.속성으로 안 쓰고 바로 속성만 쓸 수 있음

function TodoList({ $target, initialState }) {
  const $todoList = document.createElement("div"); 

  $target.appendChild($todoList);

  this.state = initialState;
}

main과 index.html

  • main: querySelector 이용해서 어느 DOM에 그릴 것인지 정하기

  • index.html: 브라우저에서 스크립트를 불러와 실행시킴

    • 스크립트들을 <head>가 아닌 <body> 안에 선언하는 이유:
      <head> 안에 넣으면 스크립트를 로딩하는 동안 브라우저 렌더링이 차단됨 (화면에 아무것도 안 보임)
      => <body> 안에 스크립트를 두면 페이지의 나머지 내용은 먼저 렌더링되고, 스크립트 다운로드 및 실행이 병행되어 사용자 경험이 좋아짐

    • 스크립트를 불러오는 순서가 굉장히 중요함 (선언된 순서대로 로딩하기 때문)

  <body> 
    <main class="app"></main>
    <script src="./src/TodoList.js"></script> // main에서 TodoList 컴포넌트를 사용하니까 얘를 더 위로 올려야함
    <script src="./src/main.js"></script>
  </body>

TodoForm 컴포넌트

  • 어떤 컴포넌트(기능)을 새로 생성한다면?
    -> 1. 해당 컴포넌트 생성
  1. 받아오는 target을 지정해주는 곳(main)에 가서 new 키워드로 객체 생성
  2. index.html에 가서 새 컴포넌트 선언해서 불러오기

form 안의 <button> 기본 타입은 "submit" -> enter 눌러도 전송됨


두 컴포넌트간의 상호작용 방법

  • TodoForm에서 입력 받은 값을 TodoList에 넣어서 화면에 보이게 하려면?
    • 방법 1. TodoForm 생성 파라미터에 TodoList 넣어 직접 참조 (TodoForm 내에서 TodoList 불러오기)
      -> TodoForm에 TodoList 컴포넌트 의존성이 강하게 생겨서 안 됨 (TodoForm 자체로 못 씀)
    • 방법 2. TodoForm 생성 파라미터에 이벤트 콜백을 넣고, text를 입력 받으면 해당 콜백을 통해 text 넘기기 (JS는 파라미터로 함수를 넘겨줄 수 있어 더욱 간편!)
      -> 컴포넌트 객체 생성 때 이벤트 콜백용 함수 만들고 파라미터로 넘겨서, 이벤트 일어나면 그 함수 불러오기
      => 컴포넌트 생성하는 곳에서만 상호작용을 정의하니까, 각 컴포넌트는 자신의 일만 하면 됨(만드는 곳이 연결하는 다리 역할)

App.js의 역할

  • 각 컴포넌트 생성 및 연결
    -> function App 안에 main에서 하던 컴포넌트 생성을 데려와서 넣고, index.html에도 App 스크립트 추가 (아래에 추가)
    -> 원래 main에 있던 컴포넌트 생성 코드들 지우고, new App()만 새로 생성 ! (index에서 App이 main보다 위에 있어야함)
    => main은 초기 데이터 정의, App의 target 등 정보 관리만 함

Client Side 데이터 저장

CookieLocal Storage 존재

  • 브라우저에 저장되는 작은 문자열(HTTP 프로토콜의 일부), 클라이언트에서 데이터를 저장하는 가장 오래된 방식
document.cookie = "language = javascript"
  • 이전 쿠키에 덮어쓰는 것이 아닌 새로 추가되는 것
    (개발자모드의 어플리케이션 -> Cookies에서 추가된 걸 볼 수 있음)
const cookies = document.cookie; // document가 getter 역할을 하기 때문에 이렇게 불러올 수 있음

console.log(cookies) // 가지고 있는 쿠키들(문자열) 다 보여줌
  • 쿠키는 긴 문자열로 저장됨 (각 쿠키는 ;으로 구분되어 있음)
    -> 불러와서 split 등으로 쪼개서 써야함
  • 따로 유효기간 지정을 안 하면 브라우저 닫을 때 쿠키도 삭제됨

  • 방법 1. expries 넣기 (GMT String 넣어야함, 한국시간 = GMT + 9 )

document.cookie - "user=songhee; expries=Wed, 18 Aug 2023 02:13:37 GMT"

const date = new Date();
  document.cookie - `expries=${date.toGMTString()}`

new Date().toGMTString: 지금 지역 기준 시간으로 변환한 GMT 시간 구하기

  • 방법 2. max-age 넣기: 생성 시점 기준으로 적어둔 초만큼 유효기간 설정 가능 (단위는 1초)
document.cookie = "user=songhee; max-age=3600" // 생성 시점 기준 1시간 동안 유효함, 그 이후에는 삭제됨
  • HTTP 요청시 헤더에 쿠키가 같이 나가기 때문에 쿠키 사이즈가 커지면 HTTP 요청 크기도 커짐
    -> 네트워크 요청할 때 데이터 많이 필요해짐
  • 사이즈에 제한이 있음
  • 여러가지 보안 취약점을 조심해야 함 (쿠키 갈취 당할 수 있음)

Local Storage

  • key, value 기반으로 Local에 데이터를 저장함

  • 도메인 기반으로 Storage 생성 (도메인 기반으로만 유효함)
    => 도메인(http://songhee.com) 같으면 다 같은 Storage 공유 (탭 여러 개여도 도메인 같으면 같은 Storage 공유)

  • 따로 삭제하거나 Storage 날리지 않으면 계속 유지됨 (브라우저 닫아도 삭제 안 됨)

Local Storage 추가 (3가지 방법)

window.localStorage.name = "songhee" // . 이용 방법
window.localStorage["name"] = "songhee" // 대괄호 이용 방법 -> [key] = value
window.localStorage.setItem("name", "songhee") // setItem(key, value) 함수 이용 방법
  • setItem 함수 이용 권장 (안전함)
    -> .이나 []를 이용해서 property를 수정하는 방법은 length, toString 등의 내장 함수들을 덮어씌울 수 있어 위험함

Local Storage 불러오기, 삭제, 전체 삭제

// window는 생략 가능

const storageName = localStorage.getItem("name") // key 불러오기
localStorage.removeItem("name") // key 세트 삭제
localStorage.clear() // 전체 삭제
  • localStorage에는 string만 넣을 수 있기 때문에(숫자 넣으면 암묵적 변환됨) JSON.stringify로 저장, JOSN.parse로 파싱해서 꺼내야함
    -> 객체를 stringify로 안 만들면 문자열로 object가 들어감 (객체 각각의 값 안 들어감)
const user = {
  name: "songhee",
  age: 25,
  hobby: "sleeping",
};

localStorage.getItem("user", JSON.stringify(user)); // 값 저장
const storageName = JSON.parse(localStorage.getItem(user)); // 불러오기 (파싱)

Session Storage

  • 전체적으로 localStorage와 같지만, 브라우저를 닫으면 저장된 내용이 삭제됨(초기화)

Storage 관리

  • 별도의 컴포넌트(storage.js)로 분리하고 하나로 모아서 관리
    -> 외부에서 값 수정 못 하게 막음 (안전성)

  • 전역 오염을 최소화하기 위해 함수들은 즉시 실행 함수로 선언
    => 즉시 실행 함수는 꼭 return으로 함수들(객체)를 반환해야함

const storage = (function (storage) {
  const setItem = (key, value) => {};
  const getItem = (key, defaultValue) => {};
  
  return { setItem, getItem };
})(window.localStorage);

😊오늘의 느낀점😊

선언적 프로그래밍 방식으로 사고하려면 기능 단위로 함수(메서드) 분리, 기능에 맞는 메서드 사용(명령형으로 나열 X), 각 기능이 혼자서도 동작 가능하게 구현이 중요한 것 같다. (코드가 간결해짐, 유지보수 쉬움, 재사용 쉬움)

메서드를 사용했을 때 단계단계에서 어떤 일이 일어나는지 예측하며 코드를 작성해야하기 때문에 공부가 많이 해야겠다는 다짐을 했다. (코드 이해하기 위해서 필수적.,,)

쉽지 않지만 각 기능이 명확하게 본인의 일만 할 수 있고, 코드를 읽었을 때 그 역할을 알 수 있도록 작성해야겠다는 생각이 들었다.

쿠키와 스토리지를 사용해 데이터를 저장하는 방법을 배웠는데, 생각보다 어렵지 않아서 많은 곳에 응용할 수 있을 것 같다.

과제를 진행하며 try-catch, 객체 해체 할당에 대해 공부해봐야겠다.

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

0개의 댓글