프로퍼티 prop drilling(내리꽂기)의 해결책은
component composition(컴포넌트 합성)입니다
특정 상황에서는 프로퍼티 내리꽂기를
이것만으로도 해결할 수도 있겠지만
대부분의 경우, 조금 후에 살펴볼
두 번째 해결책 또한
필요할 것입니다
일단 첫 번째 해결책을 알아보도록 하겠습니다
제가 여러분을 위해 준비한 이 프로젝트에서
컴포넌트 합성의 개념을 알아 보겠습니다
Shop 컴포넌트를 보면
제품 목록을 출력하는 부분은
Shop 컴포넌트가 아닌 앱 컴포넌트로 바로 이동이 가능합니다
이러한 경우 물품 추가를 위한
handleAddItemToCart 함수의 포인터가
Shop 컴포넌트로 보내질 필요 없이
Product에 바로 전달될 수 있다는 장점이 있습니다
Shop 컴포넌트를 삭제하고 싶지는 않기 때문에
그 대신 컴포넌트 합성을 통해
상품 목록을 감싸서 묶어두는 방식으로
이 Shop 컴포넌트를 refactor(재조정)하겠습니다
이것이 무슨 의미인지를 보여드리기 위해
물품 목록을 렌더링하기 위한 가짜 물품 코드에서
매핑하던 이 코드를 가져와 보도록 하겠습니다
Shop 컴포넌트에서 이 부분을 잘라낸 뒤
앱 컴포넌트로 와서
여기 있는 Shop 컴포넌트를
기존의 (self-closing)스스로 닫히는 컴포넌트가 아닌
시작 및 종료 태그를 가진 컴포넌트로 바꾸어 줍니다
그리고 목록을 출력하는 코드를
여기 앱 컴포넌트 내에 있는
Shop 컴포넌트의 시작과 종료 태그 사이에 넣습니다
이 부분을 수정했다면
dummy-products.js(가짜 물품 파일)로부터 앱 컴포넌트로
이 가까 물품 데이터를 불러와야 합니다
다행히 이 쪽에 해당 작업이 이미 되어 있습니다만
Shop.jsx 파일에서 해당 import 부분을 삭제하고
Shop 컴포넌트 파일에서 Product 컴포넌트의 import를
삭제하는 대신 그 컴포넌트를
이쪽의 App.jsx 파일에 가져오겠습니다
이 Product 컴포넌트를 불러오기 위해
./components/Product.jsx를 입력해 주면
import 작업이 이곳에 추가되어 해당 목록이
이 쪽으로 출력되는 것입니다
이제 우리가 신경 써야 하는 부분은
여기 Product 컴포넌트가 필요로 하는
알맞은 함수를 onAddToCart 속성에 전달하는 것입니다
우리가 전달하고자 하는 함수는
여기 보시는 handleAddItemToCart 함수입니다
이제 이것을 복사해서
onAddToCart의 값으로 사용할 수 있습니다
Shop 컴포넌트는 아래 내용을 감싸고 있지만
이제는 물품 출력을 위한 로직과
해당 Product 컴포넌트의 쓰임새가
모두 앱 컴포넌트에 들어 있습니다
즉 우리가 더 이상
이쪽의 handleAddItemCart 함수의 pointer(포인터)를
Shop 컴포넌트로 전달할 필요가 없다는 것입니다
대신 Shop 컴포넌트에 더 이상 필요치 않은
해당 속서을 이제 삭제할 수 있는 겁니다
이 부분도 삭제할 수 있습니다
더는 여기서 product를 렌더링할 필요가 없기 때문입니다
대신 Shop 컴포넌트에서 해 주어야 하는 것이 있는데
앞서 배운 이 특수 자식 속성을 받아서
이 커스텀 컴포넌트가
시작 및 종료 태그를 포함하여
Product 목록을 감싸 주어야 합니다
unordered list(이 순서 없는 목록)에 children을 입력하고
이와 더불어 컴포넌트 합성을 수용해서
Shop 컴포넌트를 이용해
Product 목록을 한 번 더 감싸겠습니다
이렇게 함으로써
컴포넌트 중첩을 한 층 삭제한 것인데
대신 Product 목록은 이쪽으로 출력되도록 하였습니다
이대로 저장하고 앱을 재실행하면
여전히 장바구니에 물건을 추가하거나
장바구니를 보고 편집할 수도 있습니다
그렇지만 적어도 프로퍼티 내리꽂기 문제 중
일부분을 제거할 수 있었습니다
그럼에도 이 해결책의 단점은
모든 컴포넌트의 층에 사용하기에는
적합하지 않다는 것에 있습니다
왜냐하면 이 방법을 사용한다면
결국 모든 컴포넌트가 앱 컴포넌트로 들어가고
나머지 컴포넌트는 감싸는 용도로만 사용되기 때문입니다
이대로도 작업은 가능하지만
꽤나 비대해진 앱 컴포넌트가 될 것입니다
그래서 다음 시간에는
또다른 해결책을 살펴 보겠습니다