Frontend/프로그래머스 FE 데브코스

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

BeNI 2022. 10. 31. 17:16
728x90

 

컴포넌트 방식으로 생각하기(w. To do list) 

1. To-do 리스트를 추상화 하기

- UI를 선언적으로 표현하기 위해 TO-DO 리스트를  Header, TodoFrom, TodoList, App의 4가지로 추상화 

👉 컴포넌트의 재사용 가능, 기능 추가시 간편

 

위와 같은 형태

 

1) TodoList 컴포넌트 만들기

◼ 명령형 코드 방식

function TodoList(params) {
  const $todoList = document.createElement('div');
  const $target = params.$target;
  $target.appendChild($todoList);

  this.state = params.initialState;
  this.render = () => {
    // 명령형
    let html = '';

    for(let i=0;i<this.state.length;i++){
      html += `<li>${this.state[i].text}</li>`
    }
    html += `<ul>${html}</ul>`;
    $todoList.innerHTML = html;
  }

  this.render();
}

 

◼ 함수형 코드 방식(+ es6) 

// object destructuring
function TodoList({$target, initialState}) {
  const $todoList = document.createElement('div');
  $target.appendChild($todoList);

  this.state = initialState;

  this.render = () => {
    $todoList.innerHTML = `
      <ul>
        ${this.state.map(({text}) => `<li>${text}</li>`).join('')}
      </ul>
    `
  }

  this.render();
}

 

- TodoList 함수에 setState() 메서드를 추가하여 state가 업데이트 될 때 render 되도록 해준다.

this.setState = nextState => {
    this.state = nextState;
    this.render();
}

.- main.js에서는 아래와 같이 함수를 호출한다.

const todoList = new TodoList({
  $target: $app,
  initialState: data
})

setTimeout(() =>{
  todoList.setState([
    { text:'Happy JS' }
  ])
}, 5000)

 

 

2) TodoList를 화면에 불러오기

- main.js을 작성한다. (new를 통해 TodoList를 생성한다)

const data = [
  {
    text: '자바스크립트 공부하기'
  },
  {
    text: '자바스크립트 복습하기'
  }
];

new TodoList({
  $target: $app,
  initialState: data
});

- 그 후 index.html 파일에 js파일들을 불러온다.

 

⭐ script 코드 위치는 굉장히 중요 !

  • 먼저 불러와야 되는 파일이 먼저 와야 한다.
  • 파일이 head쪽에 있으면 그 스크립트가 불러올 때까지 사용자는 빈 화면만 보임
  • body안 아래에 위치하면 내용은 불러와진다.(조금더 나은 경험을 준다.)

 

 

3) TodoForm 컴포넌트 만들기

- TodoForm의 input에 작성한 데이터가 TodoList로 들어가야한다.

- 하지만, 파라미터에 TodoList를 넣고 직접 참조하는 방식은 두 함수간의 의존성이 강하게 생김

👉 파라미터로 onSubmit 함수를 받는다.

function TodoForm({$target, onSubmit}) {
  const $form = document.createElement('form');

  $target.appendChild($form);

  let isInit = false;

  this.render = () =>{
    $form.innerHTML = `
      <input type="text" name="todo" />
      <button>Add</button>
    `
    if(!isInit) { 
      $form.addEventListener('submit', e => {
        e.preventDefault(); // form action을 막는다.

        const $todo = $form.querySelector('input[name=todo]');
        const text = $todo.value;

        $todo.value = '';
        if(text.length>1){ // 글자수 2이상일때
          $todo.value= '';
          onSubmit(text);
        }

      })
      isInit = true;
    }
  }

  this.render();
}

 

// main.js
new TodoForm({
  $target: $app,
  onSubmit: (text) => {
    const nextState = [...todoList.state, {
      text
    }]
    todoList.setState(nextState)
  }
})

- main에서는 todoList의 상태를 변경해주는 코드를 작성하여 TodoForm에서는 TodoList와의 의존성을 최소화 한다.

 

 

4) Header 컴포넌트 만들기

function Header({$target, text}){
  const $header = document.createElement('h1');

  $target.appendChild($header);

  this.render = () => {
    $header.textContent = text
  }

  this.render();
}

 

5) App.js로 화면에 그려지는 요소 관리하기

function App({$target, initialState}) {
  new Header({ $target, text: 'Simple Todo List'});

  new TodoForm({
    $target,
    onSubmit: (text) => {
      const nextState = [...todoList.state, {
        text
      }]
      todoList.setState(nextState);
    }
  })

  const todoList = new TodoList({
    $target,
    initialState,
  })

}

- main에서는 App.js를 불러온다.

const $app = document.querySelector('.app');

new App({
  $target: $app,
  initialState
})

 

👉 form의 동작

  • form에는 action이라는 속성이 있음
  • form을 전송하면 action에 전송된 url로 폼 안에 있는 입력값들을 서버로 보냄

 

 

 Client Side에서 데이터를 저장하기

1. Cookie

- 쿠키는 브라우저에 저장되는 작은 문자열로 RFC 6265 명세에서 정의한 HTTP 프로토콜의 일부

- 다른 저장 방법에 비해 가장 오래된 방식

 

1) Cookie 추가하기

document.cookie = 'KDT=is_fun';

 

2) Cookie 읽어오기

const cookies = document.cookie;

- 쿠키는 ; 문자열로 끝나기 때문에 모든 쿠키 정보를 배열에 담고 싶으면 split() 메서드를 이용

 

3) Cookie 유효기간 넣기

- 유효기간은 GMT 시간을 기준으로 하기 때문에 new Date().toGMTString() 으로 구할 수 있다.

// 하루뒤 만료되는 쿠키 설정하기
const date = new Date();
date.setDate(date.getDate() +1);

document.cookie = 'user=euna; expires=`${date.toGMTString()}`';
//document.cookie = 'user=euna; expires=Wed, 18 Aug 2021 02:30:23 GMT";

// max-age 이용하기
document.cookie = 'user=euna; max-age=60'; // 1분 뒤

- 유효기간이 없으면 브라우저가 꺼지면 같이 삭제된다.

 

4) 주의 사항

  • HTTP 요청시 헤더에 쿠키가 같이 나가기 때문에 쿠키 사이즈가 크면 HTTP 요청 크기도 커짐
  • 사이즈에 제한이 있음
  • 보안 취약점 주의

 

2. Local Storage

- key, value 기반 Local에 데이터를 저장할 수 있음

- 도메인 기반으로 Storage가 생성이 된다(도메인만 같다면 여러 탭 내 같은 Storage 공유가능)

- 삭제하거나 Storage를 날리지 않는 한 삭제되지 않음

 

1) 값 저장(3가지 방식)

window.localStorage.name = 'euna';
window.localStorage['name'] = 'euna';
window.localStorage.setItem('name', 'euna');

- setItem을 쓰는 것이 권장(property를 수정하는 방식은 내장함수를 덮어쓸 우려가 있음)

 

2) 불러오기

const name = localStorage.getItem('name');

3) 삭제하기

localStorage.removeItem('name');
localStorage.clear(); // 전체 삭제

- localStorage에는 string만 넣을 수 있기 때문에 넣을 때는 JSON.stringfy로, 꺼낼 땐 JSON.parse로 파싱하는 게 좋음

* object를 넣었을 시 Object(텍스트)가 들어감

 

 

3. Session Storage

- 전체적으로 Local Storage와 같다

- 브라우저를 닫으면 저장된 내용이 초기화됨

 

 

 

To-do 앱에 웹스토리지 추가하기

- TodoList에서 직접 로컬스토리지에 접근하여 가져오는 것은 사용자가 임의로 로컬스토리지를 변경할 위협이 있기에

  try-catch문으로 따로 함수를 작성하는 것이 좋다. (안그러면 로딩자체가 안됨)

 

- setItem() 함수에서는 key를 바탕으로 로컬스토리지에 item을 저장하고, 에러 발생시 콘솔에 찍어준다.

- getItem() 함수에서는 키와 기본값을 받아 key를 통해 로컬스토리지에서 value를 받아올 수 있으면 상태를 업데이트,

  아니라면 기본 값([])을 상태로 지정하여 화면에 불러올 수 있도록 한다.

const storage = (function(){
  const setItem = (key) => {
    try{
      storage.setItem(key, value);
    }catch(e) {
      console.log(e);
    }
  }

  const getItem = (key, defaultValue) => {
    try{
      const storedValue = storage.getItem(key);

      if(storedValue) return JSON.parse(storedValue);
      return defaultValue;

    }catch(e){
      console.log(e);
      return defaultValue;
    }
  }
})(window.localStorage)

 

- main.js 에서 함수를 불러온다.

const initialState = storage.getItem('todos', []);

- App.js의 TodoForm 생성에서 setItem()을 호출한다.

new TodoForm({
    $target,
    onSubmit: (text) => {
      const nextState = [...todoList.state, {
        text
      }]
      todoList.setState(nextState);

      storage.setItem('todos', JSON.stringify(nextState));
    }
  })

 

 

728x90