블랙커피 스터디1 문벅스 step2 상태관리 회고

짱유경·2021년 10월 31일
1

블랙커피 스터디

목록 보기
2/4
post-thumbnail

제출한 미션은 여기에서 확인할 수 있다.

🎯 step2 요구사항 - 상태 관리로 메뉴 관리하기

  • localStorage에 데이터를 저장하여 새로고침해도 데이터가 남아있게 한다.
  • 에스프레소, 프라푸치노, 블렌디드, 티바나, 디저트 각각의 종류별로 메뉴판을 관리할 수 있게 만든다.
    • 페이지에 최초로 접근할 때는 에스프레소 메뉴가 먼저 보이게 한다.
  • 품절 상태인 경우를 보여줄 수 있게, 품절 버튼을 추가하고 sold-out class를 추가하여 상태를 변경한다.
    => 품절은 되는데 한번 더 클릭하면 품절 취소가 안된다 ..

이번 세션은 직접 구현을 하려다가, 직접 구현하려면 세션 시간까지 미션을 제출하지 못할 것 같아서 슬프지만 유데미 강의를 참고해서 구현했다. (ㅠㅠ)

🐱‍🚀 상태관리

상태관리를 구현하는걸 보면 머릿속으로 이해가 대강 되지만 응용이 안되는 상태였다. ㅠㅠ 원래의 코드는(DOM을 조작하는 방식) 각각의 함수로 쪼게져있고 이벤트리스너가 호출되면 해당 함수를 호출하는 식으로 구현되어있었는데, 유데미 강의에서는 부모 컴포넌트 안에 자식 컴포넌트들이 있고 공통 상태값을 부모에서 관리하는 방식이였다.

그 과정에 있어서 각각 쪼게져있던 함수들을 App이라는 부모 함수를 생성해서 안에 포함시켰다. 관리할 상태는 App 함수 최상단에서 this로 관리해줬다.

// 원래 구조
function addMenu() {
	// code
}

function deleteMenu() {
	// code
}

$('.menu-form').addEventListener('submit', ()=>{
	addMenu();
})

// 변경한 구조
function App() {
  // 상태
  this.menu = [];
  
  function addMenu() {
      // code
      // this.menu를 참조한다.
  }

  function deleteMenu() {
      // code
     // this.menu를 참조한다.
  }

  $('.menu-form').addEventListener('submit', ()=>{
      addMenu();
  })
}

// error - App();❌ new App();⭕
App();

그런데 이 과정에서 콘솔에서 this.menu를 사용할 수 없었다는 에러가 나타났다. (!) 먼저 함수를 호출할 때 new 연산자를 사용하지 않고 App()이라고 실행했던 아주 멍청한 실수가 하나 있었다. new App()이라고 먼저 수정했다.

그러고 나서 잘 작동하는 줄 알았으나 입력 폼에다가 submit 이벤트를 실행하니 이번에도 this.menu가 참조되지 않았다. 🤔 왜 이러는지 생각해보다가 예전에 function 안에서 this를 호출하려면 바인딩해줘야 해야 하거나 화살표 함수로 작성해야 한다는 글을 봤어서 const addMenu = () => {}와 같은 방식으로 변경해주니 무사히 작동했다.

여기서 this의 중요성과 일반 function과 arrow function의 차이점을 알게 되었다. 원래도 이론적으로는 알았지만 사실 이해가 잘 안됐었고 와닿지 않았는데 직접 문제 케이스를 겪어보니 이해가 됐다. this의 참조 문제를 겪으면서 알게된 내용들은 여기에 적으면 너무 길어질 것 같아서 분리해서 작성할 예정이다.

🛒 store

문벅스 예제 강의에서 상태를 관리할때는 App함수의 this.meu 배열안에 값을 넣어 관리했다. 이때 배열 안에 들어간 값을 로컬스토리지 안에 저장해 새로고침이나 탭을 닫어도 상태값을 유지하도록 했어야 했는데, 로컬스토리지에 입/출력을 하는 기능을 sotre라는 객체로 생성해 관리하도록 했다.

const store = {
  setLocalStorage(value) {
    localStorage.setItem("menu", JSON.stringify(value));
  },

  getLocalStorage() {
    return JSON.parse(localStorage.getItem("menu"));
  },
};

나도 강의를 들으면서 단순히JSON.parse(localStorage.getItem("menu"));라고 사용하지 않고 store라는 객체 안에 함수를 만드는 이유가 궁금했는데 상태를 관리하는게 여기저기 흩어져 있으면 관리하기 어렵기 때문이었다. 그런데 이렇게 중앙에서 관리를 하는게 맞는 것 같은게, 만약 각 코드마다 localStorage.setItem("menu", JSON.stringify(value)); 이런식으로 관리했으면 부수효과가 계속해서 생성되고 에러가 나타난다면 디버깅이 더욱 어려울것 같았다.

여기서 준님이 예시용으로 리뷰를 해주신 내용은 index.js 파일에 상태를 관리하지 않고 export로 분리해 store라는 함수를 관리하는게 좋을 것 같다는 피드백이었다. 확실히 지금 단계에서는 코드의 복잡도나 기능의 요구사항이 많이 크지 않기에 한 파일에서 모든걸 관리해도 괜찮았는데, 나중에 기능 요구사항이 복잡해지고 좀더 확장에 열려있으려면 분리해주는게 편할 것 같았다.

⛔ if문 안의 return

이벤트 위임을 이용해 기능을 구현했던 것 중 if문이 여러줄 있는 코드가 있었다.

if (e.target && text == "품절") {
  soldOutMenu(e);
}

if (e.target && text == "수정") {
  editMenu(e);
}

if (e.target && text == "삭제") {
  deleteMenu(e);
}

이런식으로 if문이 여러개 있으면 각 코드가 끝날때 return;을 적어주는게 성능에 좋다고 언급하셨다.

if (e.target && text == "품절") {
  soldOutMenu(e);
  return;
}

if (e.target && text == "수정") {
  editMenu(e);
  return;
}

if (e.target && text == "삭제") {
  deleteMenu(e);
  return;
}

조건이 여러개 있을때 앞부분에서 만족하는 케이스를 찾으면 뒤의 케이스는 비교할 필요가 없기에 조건을 비교하는 시간을 줄여줄 수 있기 때문이었다. 처음 안 부분이었는데 유용한 팁이라 기록해둔다. 👍✨

🔰 고민했던 부분 - setState

react에서는 상태를 관리할때 직접 state에다가 splice나 push를 하지 않고 setState라는 함수 안에 값을 넘겨줘서 관리하는것처럼 menu라는 state를 직접적으로 변경하지 않게 하고 싶었다. 지금의 상태는, this.menu[this.currentCategory].splice(menuId, 1); 이런식으로 관리되었는데 가독성도 떨어지는 느낌이고 부수효과가 남발되는 느낌이라 좀 더 깔끔하게 관리하고 싶었다.

setState(nexState) {
	this.menu = nextState;
}

대략 이런식으로.. react에서는 상태를 관리할때 불변성을 지켜야하는만큼 menu라는 배열에서 값을 수정할때마다 이전 상태를 복사해서 넣어주는 방식으로 구현했으면 됐었을텐데, 당시에는 각 메서드마다 pushsplice같이 작동하는 방식이 달랐어서 이걸 어떻게 관리해야하나 싶었다. 기능 구현이 급급해서 정돈되지 못한 코드로 낸게 아쉬웠다.

💫 step2 미션 후기

상태관리라는 개념에 친숙하지 않은 상태로 좀 더 완벽하게 코드를 작성하고 싶어서 (기능별로 컴포넌트 분리하기..) 삽질을 엄청나게 하는 바람에 미션 제출날까지 완성된 코드가 없었다.ㅠㅠ 결국 눈물을 머금고 유데미 강의와 병행했는데, 강의를 듣고 코드를 작성하면서 상태 관리라는 개념에 좀 더 익숙해진것 같았다.

step1과의 코드를 비교해봤을때 step1은 특별한 기준을 가지고 DOM을 조작하는게 아니라 그때그때 요청에 맞게 DOM을 조작했었다. 예를 들어 어떤 node에 이벤트가 감지되면 DOM을 제거하거나 추가하는 식으로 말이다. 이런식으로 작성한 코드는 비교해보면 확실히 (1) 코드가 읽기 좀 지저분한 것 같다. (2) DOM이 조작되는 기준을 찾기 어려워서 전체 코드가 하나의 거대한 부수효과 같았다.

이런 방식에서 menu라는 상태를 기준으로, 값을 추가하고 삭제하고 그에 따라 DOM을 조작하니까 조금 더 기준이 명확한 느낌이였다. 내가 비록 불변성으로 상태를 관리하진 않았지만, 상태를 관리할때 현 상태에서 바로 push와 splice를 하는게 아니라 기존 상태를 복사한다음 새로운 상태를 비교해서 렌더링 하는 방식으로 좀 더 고도화했으면 확실히 부수효과가 줄어들고 더 코드를 관리하기 쉬울 것 같았다.

그동안 React를 자주 쓰면서 사실 상태관리라는 개념이 단순히 상태(변화하는 값)들을 좀 더 쉽게 관리한다. 이정도 밖에 몰랐고 이점이 두루뭉실하게밖에 몰랐는데, 단계적으로 진화시키면서 상태관리라는 개념에 더 친숙해진 것 같아서 좋았다.

0개의 댓글