이제 이 상태를 업데이트 하기 위해서
우리는 다른 액션을 다룸으로써
이것이 다른 상태 업데이트로 이어지도록
해야 합니다
그리고 이 작업을 이해하기 위해서는
이 두번째 요소의 도움을 받아
액션을 내보내는 것으로 시작하겠습니다
저의 경우에는 이 shoppingCartDispatch 요소입니다
여기에서는 간단하게
여기에 있는 handleAddItemToCart에
모든 상태 업데이트용 로직을 넣는 대신
리듀서로부터 돌려받은
이 디스패치 기능을 호출해서
이것을 사용해 액션을 내보내는 것입니다
액션은 여러분이 원하는 것이라면
문자열도 숫자도 괜찮습니다만
대부분의 경우에는 type(유형)이나 식별자와 같은
속성을 가진 객체일 때가 많은데
이를 통해 각각의 액션을 구분할 수 있고
리듀서 내에서 다르게 처리하기 위함입니다
여기에 저는 유형 속성을 추가하고
유형으로는 ADD_ITEM이라고 입력하겠습니다
문자열 안에 저는 이렇게 표기를 했는데
여러 리액트 프로젝트에서 사용하는 관습으로
필수적이지는 않습니다
이렇게 add-item이라고 쓰시거나
원하시는 다른 식별자를 사용해도 됩니다
저는 일단 ADD_ITEM으로 써두고
여기에 이렇게 유형을 추가해 두었으므로
이 액션이 무엇인지를 알아볼 수 있게 되었습니다
해당 액션이 실행되기 위해서는
특정 데이터를 필요로 하는데
요컨대 장바구니에 추가할 물건에 대한 정보입니다
그렇기 때문에 이 객체에
두 번째 속성을 추가하겠습니다
이름은 무엇이든 상관 없지만 payload라는 이름을 자주 사용합니다
물론 id 등 다른 이름도 괜찮습니다
저는 일단 payload로 설정하겠습니다
payload는 id입니다여기의
제가 매개변수로 받는 이 id를
이 액션 오브젝트에 payload로 설정하는 것입니다
여기에서 해당 액션을 내보냈으니
이제 리듀서 기능으로 돌아가 보겠습니다
액션을 내보낼 때마다
이 기능이 실행되어 해당 액션이 이루어집니다
dispatch 기능에 전달된 이 인자는
예를 들자면 여기 이 객체가
이 액션 매개변수에 값으로 전달되는 것입니다
그러므로 리듀서 기능에서 우리는
if 를 이용해 action.type 또는 유형 외에
여러분이 선택한 식별자 속성이
ADD_ITEM과 같은지를 확인하고
만약 그렇다면 그에 따라 상태를 업데이트할 수 있습니다
더 많은 액션을 갖고있다면, 여러 if 체크를 추가해서
예를 들어 UPDATE_ITEM 등을 확인해 볼 수 있습니다
저는 하나의 액션만 가지고 있기 때문에
이것만 내보내겠습니다
이제 여기에 이전 상태 스냅샷(snapshot)과 달라진
상태를 반환하려 합니다
정확하게 하기 위해, 여기 아래의 handleAddItemToCart의
상태 업데이트용 함수에 들어있는
로직을 복사하겠습니다
이렇게 코드를 복사해도 되지만
정확도를 위해 코드를 잘라내고
setShoppingCart 기능을 지워버리면
이제 여기 handleAddItemToCart에서만 dispatch를 사용하고
그 외에는 아무것도 하지 않게 됩니다
잘라낸 코드는 여기에 있는
ShoppingCartReducer 안에 붙여넣겠습니다
다만 약간의 조정이 필요한데
여기에 있는 prevShoppingCart 값은
이 위쪽의 상태 매개변수가 되었고
이것은 우리가 리액트로부터 받는
보장된 가장 최신 상태이기 때문입니다
여기에 있는 id는 액션으로부터 추출이 가능하므로
payload라는 속성 아래에 보관하겠습니다
다시 말씀드리지만
만약 dispatch 사용 시 액션에 다른 이름을 붙이셨다면
즉 여기에 payload가 아닌 다른 이름을 사용하셨다면
그 이름을 여기에 넣어 주셔야 합니다
저는 여기에 id를 다시 사용했습니다
이제 이것도 action.payload가 되었고 이쪽도 마찬가지입니다
그리고 이제 items를 updatedItems로 설정해서
업데이트된 상태 스냅샷을 반환하겠습니다
만약 다수의 속성을 가진, 좀더 복잡한
상태 객체를 가지고 있다면
다른 값을 잃어버리는 일이 없도록
먼저 예전 상태를 펼쳐서 복사해 주고
그 이후에는 액션이 실행되었을때 상태에 업데이트된
하나의 값을 업데이트하면 됩니다
우리는 상태에 하나의 값만
있기 때문에 이것이 필요하지는 않지만
좀더 복잡한 상태 객체라면
데이터를 잃지 않도록 이것을 추가해 두는 것이 좋습니다
이제 여기 있는 ADD_ITEM 액션을 다루겠습니다
우리가 상태 업데이트를 위해 써야 하는 코드는
이전에 비해 적지는 않습니다만
이제는 리액트 컴포넌트 밖의
리듀서 기능에 들어가 있다는 점이 다릅니다
그리고 특별한 함수 형태를 써야한다는
생각을 할 필요가 없습니다
리듀서 기능으로 우리는 가장 최신의
상태 스냅샷을 자동으로 받을 수 있기 때문입니다
이번에는 장바구니 물품의 수량을 업데이트 해주는
또다른 상태 업데이트 기능을
옮겨 보도록 하겠습니다
이를 위해서 여기 이 코드를 모두 잘라내고
handleUpdateCartItemQuantity 안에 있는
이 setShoppingCart를 지워주고
대신 또다른 액션을 내보내기 위해
shoppingCartDispatch를 사용해 주겠습니다
위에서 식별자 속성으로 사용했던대로
여기에도 마찬가지로 type을 입력하겠습니다
이번에 UPDATE_ITEM으로 이름을 짓는 이유는
이미 장바구니에 들어있는 물건을 업데이트 하기 때문입니다
payload는 이제 두 개의 값으로 구성됩니다
이 두개의 값을 이 액션 객체에
개별적인 추가 속성으로 각각 전달할 수도 있지만
일단은 이 payload를 유지해서
중첩 객체로 모아두겠습니다
여기 productID가 있고
이쪽의 productID와 같도록 해두고
그리고 수량인 amount를 입력해 줍니다
자바스크립의 단축키로
이렇게 좀더 짧게 쓰는 방법도 있는데
리액트의 방법은 아니고
자바스크립트의 일반적인 기능입니다
만약 속성의 이름이
값을 가진 변수와 같다면
이는 해당 속성 아래에 두어야 하고
코드를 이렇게 줄일 수 있습니다
이제 UPDATE_ITEM 이라는 유형이 생겼으니
리듀서 기능에
이렇게 두번째 if 체크를 추가해서
action.type과 지금 막 내보낸 액션인
UPDATE_ITEM이 동일한지를 확인합니다
그리고 나서 잘라낸 상태 업데이트용 코드를
여기에 있는 if 블록에 붙여넣어 줍니다
이번에는 예전의 state.items를 복사하는 것으로 시작하는데
useState의 도움을 받은
상태 업데이트와 마찬가지로
메모리에 있는 지난 상태는 절대 직접 변형시키면 안됩니다
대신 항상 이렇게 복사해 주시는 것이 좋습니다
productID를 가져오기 위해서는
action.payload를 입력하고 productID를 덧붙여줍니다
amount의 경우 action.payload.amount 입니다
비록 여기에 필요하지는 않지만
새로운 상태 객체를 만들기 전에
데이터 손실이 없도록
한번더 지난 상태를 복사해 줍니다
여기 리듀서 기능을 보시면
업데이트 로직이 있습니다
그러므로 이 컴포넌트의 useState 훅을
삭제할 수 있게 되었는데
이제 모든 것을 useReducer를 통해 관리하기 때문에
import에 있는 useState를 삭제하더라도
모든 것이 제대로 동작할 것이기 때문입니다
이제 여기 이벤트 핸들러(event handler) 함수에 있는
액션을 이렇게 내보내 주면
해당 액션들이 리듀서 기능을 실행시킬 것입니다
여기에 자리한 각각의 로직이 있는 여러 if 블럭은
그에 맞추어 상태를 업데이트해 줄 것이고
이 shoppingCartState는
이것과 같은 컨텍스트를 통한 공유로
앱에 다시 전달될 것입니다
이 useReducer 훅을
다른 컴포넌트에서도 사용할 수 있다고
말씀드리고 싶지만
그것은 이 컨텍스트 기능에 연결되어 있지 않습니다
함께 사용되는 경우는 있지만
각자 따로 동작하기 때문입니다
useReducer는 상태를 필요로 하는
리액트 컴포넌트라면 어디에서나 사용이 가능합니다
이제 모든 것을 저장하고 새로고침해 보면
아무런 오류가 없고, 장바구니에 물건을 추가해 보아도
문제없이 동작하고
수량 조절도 잘 작동하고 있습니다
이렇게 이전과 동일한 결과물을 얻었고
이번에는 컨텍스트와 더불어 useReducer 훅을 써보았는데
이 훅의 사용은 필수가 아니기에 여러분의 선택에 달려 있습니다