상태 관리 (feat. NEXT STEP 자동차 경주 미션)

이현정·2022년 7월 29일
0

NEXT STEP step.1 을 머지하며 상태 관리를 할 수 있는 데이터 모델을 만들어보면 좋겠다는 피드백을 들었다. 프엔이라면 꼭 알아야 하는 상태관리에 대해서 이번 기회에 공부해 보면 좋을 것 같다는 리뷰어님 조언에 따라 상태관리에 대해 나름대로 알아보고 정리해보는 시간을 가졌다.

상태 관리를 듣자마자 제일 먼저 React 의 useState 훅과 recoil 라이브러리가 생각났으나 이번 미션은 그 어떤 라이브러리도 허용되지 않은 바닐라 자스로만 해야했다.

상태 관리는 무엇이고, 바닐라 자바스크립트로는 어떻게 상태관리를 할 수 있을까?

상태와 상태관리

상태는 무엇이고 상태관리는 무엇인지 알아보자.

상태란 무엇인가?

상태는 영어로는 state라고 하는데 데이터라고 부르는게 이해가 쉽다는 을 보았는데 여기에 동의한다.

객체가 가지고 있는 데이터 또한 상태라고 할 수 있다.

해당 글의 예시를 보면 Car 클래스를 만든다고 가정하면 자동차의 상태(데이터)는 color와 type 가 된다.

type CarType = 'suv' | 'bus' | 'truck'
class Car {
  color: string // 자동차의 색상 상태
  type: CarType // 트럭인지 버스인지 등 자동차의 종류 상태
  constructor(color: string, type: CarType) {
    this.color = color
    this.type = type
  }
}

=> 결론: 상태 = 데이터 라고 봐도 무방하다.

상태 관리란

그렇다면 상태관리란 무엇일까?

=> 데이터에 맞춰 적절하게 UX와 UI를 설계하고 구현하는 것

시중에는 이미 redux, recoil 등 상태관리를 도와주는 다양한 프레임워크 또는 라이브러리가 나와있다.

그렇다면 바닐라 자스로는 어떻게 상태를 관리할 수 있을까?
아래와 같은 방법들이 있다:

로컬 스토리지(Local Storage)

로컬스토리지 : 사용자(로컬)에 저장하는 임시저장소. 영구적. windows 전역 객체의 LocalStorage라는 컬렉션을 통해 저장, 조회가 이루어진다.

세션스토리지 : 임시적. windows 전역 객체의 sessionStorage라는 컬렉션을 통해 저장, 조회가 이루어진다.

클로저(Closure)

클로저: https://edu.nextstep.camp/s/M4ILAt8c/ls/7ARXIHYj
=> 는 "데이터를 안전하게 관리할 수 있는 방법 중 하나"

mdn 에 따르면 "클로저는 어떤 데이터(어휘적 환경)와 그 데이터를 조작하는 함수를 연관시켜주기 때문에 유용하다. 이것은 객체가 어떤 데이터와(그 객체의 속성) 하나 혹은 그 이상의 메소드들을 연관시킨다는 점에서 객체지향 프로그래밍과 분명히 같은 맥락에 있다."

"이렇게 할 수 있는 상황은 특히 웹에서 일반적이다. 프론트 엔드 자바스크립트에서 우리가 쓰는 많은 코드가 이벤트 기반이다. 우리는 몇 가지 동작을 정의한 다음 사용자에 의한 이벤트에(클릭 혹은 키 누르기 같은) 연결한다. 우리의 코드는 일반적으로 콜백으로 첨부된다: 이벤트에 응답하여 실행되는 단일 함수다."

스토어

이전에 작성했던 포스트에도 언급했지만, 현대적인 프론트엔드 개발에서 제일 중요한 것은 바로 상태관리 라고 해도 무방하다. Vue나 React 같은 프론트엔드 프레임워크의 주된 목적 중 하나가 상태를 기반으로 DOM을 렌더링 하는 것이기 때문이다.

이 때 중앙 집중식 저장소 역할을 하며 예측 가능한 방식으로 상태를 변경 할 수 있다면 편하지 않을까? => Redux, Vuex

중앙 집중식 저장소를 간단하게 스토어(Store) 라고 표현해보자. Store를 구현하기 위해 먼저 저장소(Store)와 컴포넌트(Component)의 관계를 잘 살펴봐야 한다.

  • Store는 여러 개의 컴포넌트에서 사용될 수 있다..
  • Store가 변경될 때, Store가 사용되고 있는 Component도 변경되어야 한다. => 옵저버 패턴

옵저버 패턴

옵저버 패턴은 데이터관리를 도와줄 수 있는 또 하나의 방법 정도라 생각된다.

옵저버 패턴(Observer Pattern)을 사용하면 위와 같은 고민을 하지 않아도 된다. 애초에 View는 상태 변화를 알아채려고 노력하지 않아도 된다. 관심있는 상태를 대해 구독(Subscribe)해놨기 때문이다.

옵저버 패턴에서는 상태와 같이 관심의 대상이 되는 것을 'Subject(대상)' 라고 부른다. 'Subject' 는 관찰자들(Observers)과 1 대 다의 관계를 갖는다. 즉, 'Subject'가 변경되면 이를 관찰하고 있는 '모든' 관찰자들은 각각 자동으로 알림을 받는다(Notify).

위키 피디아에 따르면 옵저버 패턴의 핵심은 옵저버 또는 리스너(listener)라 불리는 하나 이상의 객체를 관찰 대상이 되는 객체에 등록시켜 각각의 옵저버들이 관찰 대상인 객체가 발생시키는 이벤트를 받아 처리한다.

즉, 어떤 객체의 상태를 다른 객체에게 알려 해당 객체가 변경된 상태값을 인지하고 동작을 처리하도록 알려주는 것을 의미한다. 이러한 디자인 패턴은 이 상태값이 변경될 때, 상태값을 참조하고 있는 옵저버 객체들이 변경된 상태값을 누락없이 인지하도록 만들 수 있다는 장점이 있다.

요약

어려웠다. 그래도 요약해 보자면...

  • 상태 = 변하는 데이터
  • 상태 관리 = 변하는 데이터를 처리하는 방식.
    => 사용자가 입력하는 값(즉 변하는 값)에 따라 바뀌는 상태들을 한 데 모아 관리하는 것.
  • 그렇다면 FE에게 상태관리란?
    => 데이터에 맞춰 적절하게 UX와 UI를 설계하고 구현!
  • 어떻게 상태관리를 할 수 있을까?
    => 로컬스토리지, 클로저, 옵저버 패턴, 스토어 등...

TODO

  • local storage
  • useState 훅 까보기 => https://goidle.github.io/
  • 클로저 개념 이해하기
  • 이벤트루프
  • RequestAnimationFrame 과 setInterval 의 차이
  • 프로미스/비동기 => async/await => setTimeout() 를 구현(연습)
  • redux 공부해보기 =>

Reference

클로저와 옵저버 패턴
https://www.youtube.com/watch?v=45TeJEmcqk8
https://www.youtube.com/watch?v=T-xfEbDORng
https://junilhwang.github.io/TIL/Javascript/Design/Vanilla-JS-Store/#_2-observer-pattern%E1%84%8B%E1%85%A6-%E1%84%83%E1%85%A2%E1%84%92%E1%85%A2-%E1%84%8B%E1%85%B5%E1%84%92%E1%85%A2%E1%84%92%E1%85%A1%E1%84%80%E1%85%B5
https://velog.io/@dosomething/%ED%81%B4%EB%A1%9C%EC%A0%80%EB%A5%BC-%ED%86%B5%ED%95%9C-%EC%98%B5%EC%A0%80%EB%B2%84-%ED%8C%A8%ED%84%B4

참고코드
https://github.dev/next-step/js-racingcar/pull/100/files#diff-fe4793b7e17a5202a5a3ea5ea96192a7940108dd9c82711fe490cb852093cca5
https://365kim.tistory.com/89

LocalStorage
https://github.com/machao/localStorage/blob/master/storage.js
https://github.com/coolaj86/node-localStorage
https://github.com/ropnop/tokenstorage

state-management
https://github.com/hankchizljaw/vanilla-js-state-management
https://github.com/VictorTaelin/PureState
https://github.com/arnelenero/simpler-state

https://joonfluence.tistory.com/473
https://velog.io/@jjunyjjuny/%EC%A7%A7%EC%9D%80-%EC%83%9D%EA%B0%81-%EA%B0%99%EC%9D%80-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%8B%A4%EB%A5%B8-%EB%AA%A8%EC%8A%B5

keyword
Object.defineProperty
Proxy
Object LifeCycle
EventStore, EventEmitter

0개의 댓글