나는 고민을 하였다. Backtest 페이지에서 Input을 감싸고 있는 컴포넌트가 3종류가 있고, 3종류의 컴포넌트 내부에는 다수의 input 값을 가지고 있을 때, 어떻게 input을 관리하면 좋을지 고민했다.
그렇게 하다가 생각해낸 방법이 각 컴포넌트의 input 값의 name을 가지는 객체로 input들의 상태를 관리하기로 했다.
전역상태와 input 상태
나는 전역상태를 직접 onChange 이벤트가 일어날 때 마다 바꿔주는 코드를 작성했었다. 전역상태는 최소한으로 조작을 해야지만 에러가 덜 발생하기 때문에 최종적으로 저장 버튼을 클릭했을 때만 전역상태에 저장하기로 했다.
그래서 input 상태를 객체로 가지고 저장 버튼을 클릭했을 때, 전역 상태 update 함수에게 input 상태를 파라미터로 전달하도록 구현하였다.
소감
처음에는 그 많은 input을 직접 전달해줘야하나 … 걱정을 했었다. 하지만 객체로 input을 관리하고, input 마다 name 속성을 사용하여 onChange 이벤트로 controlled input을 다룰 수 있다는 것을 알게되어서 앞으로 다중 input 상태관리는 이러한 방법으로 접근하면 된다는 것을 알게되었다.
// Props<T>는 ComponentPropsWithoutRef<T>에 이 값을 그대로 넘겨준다. // 그리고 커스텀 프로퍼티 내부의 as에도 T 타입을 바인딩해준다. typeTextProps<T> = Combine<TextBaseProps<T>, ComponentPropsWithoutRef<T>>;
하지만, 이는 오류를 발생시킨다. ComponentPropsWithoutRef가 받을 수 있는 제네릭 타입이 ElementType으로 정해져 있기 때문이다.
즉, 이 중 한곳이라도 T에 대해서 명확하게 알 수 있다면 나머지 부분에서도 자연스럽게 추론이 가능하다.
as 프로퍼티로 타이핑 추상화 하기
as라는 프로퍼티는 Text 컴포넌트 뿐만 아니라 다양한 컴포넌트에서도 사용될 수 있기에 이 부분을 최대한 추상화 해둘 필요가 있다.
1 2 3 4 5 6 7 8
// 텍스트 컴포넌트의 프로퍼티 typeTextBaseProps = { typography?: string; };
// T 타입을 추론할 수 있는 as 프로퍼티를 자동으로 포함하고 // T 타입으로 HTML 엘리먼트 속성까지 타이핑 해주는 OverridableProps! typeTextProps<T extendsElementType> = OverridableProps<T, TextBaseProps>;
OverridableProps 타입은 특정 컴포넌트가 as 프로퍼티를 사용하여 HTML 요소 이름을 받고 내부적으로 해당 요소의 속성 타입을 찾아 바인딩해주는 함수이다.
이렇게 필요한 부분을 추상화해두면 필자가 아닌 다른 개발자는 ComponentPropsWithoutRef을 사용해야한다던가 Combine 타입을 사용할 때 타입 변수 T를 ElementType으로 제한해야한다던가 하는 귀찮은 부분을 생각하지 않고도 as 프로퍼티를 쉽고 빠르게 추가할 수 있을 것이다.
위 코드에서 sticky가 fixed로 고정되는 임계기준점은 scroll 클래스를 가진 div 박스이다.
scroll 클래스가 있는 박스는 스크롤이 할 수 있을 만큼 길이가 길어서 스크롤 하여 해당 임계점에 도달하는 순간 fixed로 변하게 된다.
처음에 헷갈린 점은 overflow:auto 속성을 parent 클래스를 가진 박스로 옮겼는데 아무런 일도 일어나지 않아서 당황했다. 그 이유는 parent 클래스를 가진 박스 내부가 스크롤이 되었을 때 해당 박스를 기준으로 고정되는 것인데, parent 클래스를 가진 박스는 스크롤이 될만한 높이를 가지고 있지 않아서 아무런 일도 발생하지 않았던 것이다.