최근 총 3개의 제품을 효과적으로 개발할 수 있도록 하기 위해 컴포넌트들을 제품 코드에서 분리해 스토리북과 npm 패키지로 관리하기 위한 작업을 마쳤다.
관리되어야 할 컴포넌트들의 컨셉에 대해 많은 고민을 했고 그렇게 설정한 내용들에 대해 글로 남겨보려 한다.
렌더링 최적화
일반적으로 값을 입력받는 컴포넌트들은 해당 컴포넌트 상위 컴포넌트에서 state를 전달받아 사용되는 경우가 많다.
하지만 state를 외부에서 전달받아 사용하게 되면 state를 지니고 있는 상위 컴포넌트 하위 에 있는 모든 컴포넌트들에 재렌더링이 발생한다.
bad-render
불필요한 재렌더링 발생
이런 문제점을 해결하기 위해 react-hook-form과 같은 라이브러리가 있지만 해당 라이브러리가 제시한 구조가 번거롭고 Validation 자유도 역시 그렇게 좋지 못하다고 생각해서 입력을 받는 모든 컴포넌트들이 자체적으로 state를 가지게 함으로써 이 문제를 해결했다.
모든 입력을 받는 컴포넌트들이 내부적으로 state를 가지게 되면 굳이 컴포넌트 외부 state를 수정하지 않고도 다음과 같이 원하는 입력을 화면에 표시할 수 있다.
기본적으로 Textbox 내부 로직에서는 외부에서 전달받은 value의 state가 변경되면 해당 값을 반영하도록 설계했지만 외부 state를 사용하는 경우 내부 state가 불필요해지므로 외부에서 state를 전달받았을 때는 내부 state를 비활성화하는 valueSync 옵션을 제공했다.
<Textboxvalue={formData.text}onChange={(value)=>setFormData({...formData, text: value })}valueSync/>
이렇게 설계된 컴포넌트들로 페이지를 구성하면 다음과 같이 실제로 값이 수정되는 컴포넌트에서만 재렌더링이 발생하도록 할 수 있다.
good-render
실제 값이 수정되는 컴포넌트만 재렌더링이 발생
이렇게 컴포넌트 자체적으로 state를 관리하면서 Input 컴포넌트들에 공통적으로 적용되어야 할 Validation 등을 고차 컴포넌트(Higher-Order-Components)를 표방한 함수에 분리해 두었다.
해당 attachCommonProps 함수는 설계한 Input 컴포넌트들이 공통적으로 제공해야 하는 Validation 로직이나 Label 혹은 Tootip을 추가하는 등의 로직을 담고 있다.