[TIL] 상태 관리

ㅜㅜ·2022년 11월 1일
2

Today I learn

목록 보기
44/77
post-thumbnail

상태 관리

  • 전역 상태 (Global) : 프로덕트 전체 혹은 여러 컴포넌트에서 관리되는 상태 (ex: 사이트 다크 모드, 언어 설정(국제화) 기능 )
  • 지역 상태 (Local) : 특정 컴포넌트 안에서만 관리되는 상태 (다른 컴포넌트와 데이터 공유하지 않는 Form 데이터는 대부분 로컬 상태임 input box, select box 등)
  • 전역 상태에서 데이터 무결성 (Single source of truth)
    : 동일한 데이터는 항상 동일한 곳(출처)에서 데이터를 가지고 오도록 해야 함.
  • 상태 관리를 위한 툴 : React Context, Redux, MobX
    ⇒ 전역 상태 저장소를 제공
    ⇒ props drilling 문제 해결
    ⇒❗️상태 관리 툴이 반드시 필요한 것은 아님. (장단점 인지하고 쓰자)

  • props drilling : 굳이 해당 상태가 필요하지 않음에도 자신의 하위 컴포넌트에 props를 전달해주기 위해 props를 전달 받는 것

    코드 가독성, 코드 유지보수면에서 나쁘고, 불필요한 컴포넌트들의 리렌더링 발생. (전역 상태 저장소가 있다면 어디서든 해당 저장소에 접근 가능하므로 이런 문제 해결 가능)





🤔 과제 : CMarket

과제 시작 전 지시사항에 그림을 직접 그려보면 좋다고 적혀있었다.
그림을 그릴까 말까 생각하던 중, 직접 과제 파일을 받아서 읽어보니... 이건 그려보는 게 낫겠다 싶어 혼자 끼적여 봄.

처음에 과제를 받았을 땐 확실히 함수들도 많고, 컴포넌트들도 많아서 뭐가 뭐지 싶었는데, 직접 그려보고 나니 어떤식으로 기능이 구현되고 있는지가 보였다. 아무래도 직접 회사에서 일을 할 때는 내가 처음부터 코드를 짜기 보다는 남들이 이미 만들어둔 코드를 읽는 것부터 시작할 것 같아서 이런 경험도 중요하다는 생각이 든다.

구현 할 기능

  1. handleClick 함수 구현.
  2. Nav 엘리먼트에 장바구니에 들어간 아이템의 수만큼 count 되도록 구현.
  3. handleQuantityChange 함수 구현.
  4. handleDelete 함수 구현.


구현


🟡 handleClick 함수 구현

handleClick 함수는 ItemListContainer 엘리먼트 내부에 존재하며,
Item 엘리먼트가 이 함수를 props로 받아간 다음, Item의 '장바구니에 담기'버튼의 onClick 속성에 연결된다.

장바구니에 담기 버튼이 클릭되면, 해당 제품의 이벤트 객체와 id가 이 함수로 전달되는데, id를 이용해서 전역 상태인 cartItem 배열을 수정해서 결과적으로는 장바구니에 해당 제품이 담기도록 해야한다.

const handleClick = (e, id) => {
    const found = cartItems.filter((el) => el.itemId === id)[0];
  //found는 cartItems 배열에서 함수에서 전달인자로 받은 id값과 같은 id를 가진 상품이 있는지 찾는다.
  //이미 같은 상품이 장바구니에 존재한다면 담긴 상품의 수량만 변경한다.
  //장바구니에 존재하지 않는 상품이라면 해당 상품의 id값과 quantity값을 설정한 새로운 객체를 배열에 추가해준다. 

    if (!found) {
      setCartItems([
        ...cartItems,
        {
          itemId: id,
          quantity: 1,
        },
      ]);
    } else {
      setCartItems(
        cartItems.map((el) =>
          el.itemId === id
            ? {
                itemId: id,
                quantity: el.quantity + 1,
              }
            : el
        )
      );
    }
  };


🟡 Nav 엘리먼트 구현

<span id="nav-item-counter">{cartItems.length}</span>

Nav.js 파일 속 위 span 태그가 Nav의 보이는 숫자 카운터를 가지고 있는 부분이다.
cartItems 상태에는 장바구니에 들어 있는 상품 정보가 객체로 만들어져 있고, 그 객체들이 배열을 이루고 있다.
그러므로 해당 배열의 길이를 연결해주면 cartItems에 변동이 있을 때 Nav에도 반영이 된다.



🟡 handleQuantityChange 함수 구현

handleQuantityChange 함수는 CartItem 엘리먼트에 props로 전달되어 input 태그에서 값이 변경 될 때, onChange 이벤트가 있을 때 실행되는 함수이다.
함수는 전달인자로 이벤트의 타겟이 되는 태그의 value 값을 number 형태로 바꾼 값과, onChange 이벤트가 일어난 수량 칸의 주인인 물건의 id를 받는다.

어떤 물건의 수량이 변경될 경우에 cartItem을 map으로 순회하면서 요소의 itemId와, 수량이 바뀐 물건의 id를 비교해서 동일한 경우 해당 요소의 itemId는 그대로 넣어주고, quantity 키의 값을 받아온 quantity 값으로 설정해 리턴해주어야 한다. 그리고 바뀌지 않은 물건들 역시 return 해주어야 하기 때문에 그 경우에는 바뀐 것 없이 그대로 el를 리턴한다.

이렇게 cartItems를 map함수로 순회한 뒤 반환된 배열을 가진 변수가 newCartItems이고, 이를 상태변화 함수인 serCartItems에 넣어주면 된다.

 const handleQuantityChange = (quantity, itemId) => {
    //cartItems에서 id에 해당하는 제품을 찾는다
    //찾은 제품의 quantity 속성의 값을 quantitiy 인자로 받아온 값으로 바꾼다

    const newCartItems = cartItems.map((el) => {
      if (el.itemId === itemId) {
        return { itemId: itemId, quantity: quantity };
      } else {
        return el;
      }
    });
    setCartItems(newCartItems);
  };


🟡 handleDelete 함수 구현

handleDelete는 말 그대로 장바구니에 담긴 물건들의 삭제 버튼을 눌렀을 때 장바구니에서 해당 상품이 삭제되도록 만드는 함수이다. 이 함수 역시 CartItem 엘리먼트에 props로 전달된다.

삭제버튼을 누른 물건의 id를 전달인자로 받기 때문에 cartItems에서 해당 id에 해당하는 물건을 제외한 나머지 물건들을 가진 배열을 반환해서 setCartItems 함수에 전달해주면 된다.
나머지 물건들만 받는 것은 filter 함수를 통해서 가능하다.

함수 자체의 구현은 어렵지 않았으나 안에 있는 setCheckedItems라는 checkedItems 상태(체크 박스에 체크가 되어 있는 물건들의 목록을 가진 상태임) 를 변경하는 함수가 왜 있는지 궁금했는데, 아이템을 삭제할 경우 체크가 되어 있는 물건들의 목록에서도 삭제되어야 하기 때문이었다.

const handleDelete = (itemId) => {
    setCheckedItems(checkedItems.filter((el) => el !== itemId));
    //아이템을 삭제하면 체크박스가 해제되는 것 (체크 되어 있는 애들 리스트에서도 삭제해줘야 하니까 )
    let deletedCartItems = cartItems.filter((el) => el.itemId !== itemId);
    setCartItems(deletedCartItems);
  };
profile
다시 일어나는 중

0개의 댓글