(21.11.16) Antd Input value를 mobx store로 관리하기
도깨비젤리
·2021. 11. 16. 22:47
작은 지식이라도, 하루에 하나씩.
한 줄 요약
🦄antd의 Input 컴포넌트가 깊게 nest된 mobx observable 값을 감지 못할 수 도 있다.🦄
🦄Input 컴포넌트와 mobx를 동시에 사용한다면, React.state를 사용하거나, Form 컴포넌트에 Input의 관리를 위임하는 것이 낫다.🦄
본문
목표: 회원 정보 테이블에 등록지를 수기로 입력하고, 입력 결과를 저장할 수 있게 하는 Input 요소 넣기
엊그제 회사에서 개발 요청이 들어왔다. 내용은 다른게아니라, 관리자 계정이 열람할 수 있는 테이블에 회원들의 등록지를 수기로 입력할 수 있는 column을 만들어 달라는 것이였는데, 나름 antd 짬바가 생겼다고 생각해서 금방 끝날 것이라 생각했는데, 예상 외로 훨씬 복잡하고 어려운 점이 많아서 간신히 오늘 마무리를 지을 수 있었다.
이에 이번 태스크를 마치며 느꼈던 점을 정리해본다.
1. DOM API를 쓰지마라
해당 과제를 달성하기 위해 먼저 DOM API를 사용했다. DOM API를 지양하라는 말을 들어보기도 했지만, 그래도 급한 문제를 빠르게 해결 할 수 있는 (DOM을 직접 조작하므로 구현 난이도가 낮다) 방법이므로, 기존 코드를 크게 훼손시키지 않고 간단하게 구현이 가능해 해당 솔루션을 우선적으로 고려했다.
그러나, 해당 코드는 박한 평가를 받았다. 나는 DOM API를 쓰지말라는 이유가 "옛날 방식이니까 쓰지마라~"라는 뉘앙스인줄 알았는데, 알고보니 실질적인 문제를 가지고 있었다.
- 가상 DOM을 조작하는 React 환경에서 실제 DOM을 조작한다면 관측할 수 없는 부분에서 에러가 날 수 있다는 것
- DOM API 자체가 너무 복잡하고 더럽다는 것.
- 일부 기기(PDA,휴대폰)등에서 제대로 동작하지 않을 수 있다는 것.
이와 같은 문제 때문에 DOM API를 사용한 해결책은 폐기 되었다.
2. 가급적이면 controlled Component를 사용해라
React의 컴포넌트를 설명할 때, Uncontrolled Component와 Controlled Component라는 개념이 있다.
이는 React의 State를 '신뢰 할 수 있는 단일 소스 (Single Source of Truth)'로 관리하려는 설계 원칙에서 파생된 용어인데, 요약하자면, React에서 사용되는 데이터는 모두 React 내부에서, 쉽게 말하자면 개발자가 IDE 환경에서 이리 바꾸고 저리 바꿀 수 있어야 한다는 것이다.
그렇지만, HTML 엘리먼트 중에서는 자체적인 data를 가지는 친구들이 있다. <form>의 엘리먼트들이 대표적이다. (ex. <input>,<textarea>,<select>등..)
이 친구들은 유저가 DOM에서 어떤 정보를 입력하거나 선택하는 경우, 해당 정보를 자체적으로 보관하게 되는데, 이는 위에서 언급한 React의 핵심 설계원리인 '신뢰 할 수 있는 단일 소스' 원칙에 위배되는 상황이 된다.
위와 같은 컴포넌트들을 Uncontrolled Component라고 한다. 개발자가 유저가 입력한 정보에 접근하기 위해서는 실제 DOM에 접근 할 수 있는 방법이 필요한데, input 태그에 딸린 ref가 그것이다.
하지만, 이런 컴포넌트는 실시간으로 user 정보를 관리하는 것이 아니기에, 디테일한 조작 (ex. 입력이 완료되기 전까지 버튼을 숨기는 것 등)은 어렵다.
한편, controlled component는 element의 value를 component의 prop으로 설정한 다음, 이 prop을 조작하는 것으로 state를 관리한다. 위 코드를 보면 input의 value가 this.state.name이라는 React.state로 되어 있고, 값이 변할 때마다 onChange가 트리거 되면서 state를 수정한다. 결과적으로, 개발자는 this.state.name 이라는 값으로 user의 입력값에 접근할 수 있다.
아하! 나는 실시간 정보 관리가 필요하므로 Controlled component를 제작하면 되겠군!
우리는 React.state 대신에 mobx observable로 상태를 관리하니까 그 부분만 바꾸면 되겠지??
따로 컴파일 에러나 런타임 에러가 난 건 아니였는데, Input의 값을 변경해봐도 변경된 값이 화면에 그려지지 않는 에러가 발생했다. 혹시나 상태 변화를 감지 못하는 건 아닐까 해서 mobx DevTools도 확인해봤지만, 값은 제대로 변하고 있지만, 변경되고 있는 값이 DOM에 반영되고 있지 않았다.
결론만 스트레이트 하게 얘기하자면, mobx의 observable이 이중 삼중으로 깊게 nest되어 있다면 antd의 Input 컴포넌트가 변화를 감지 못한다. "프레임워크 <--> 라이브러리 호환이 안되서 안된다" 라는 결론이 허무하기도 하지만 자체적인 데이터를 가지는 Form element family의 특성과 회사에서 사용하고 있는 데코레이터 기능이 아직 실험적인 단계라는 걸 생각해보면 뭔가 전혀 납득 안되는 이야기는 아닌 것 같고.... 아무튼 뭔가 의심은 가는데 무지의 소치로 찝찝한 맛이 남는다.
** 여담으로, Input 태그를 uncontrolled component로 바꾸면 제대로 잘 동작한다. value가 아닌 defaultValue가 state를 따라가게 하면 수정도 잘되고, 내가 구현한 저장 기능도 잘 되는데....문제는 테이블에 sorter를 실행시켜 table의 정렬 순서를 바꾸면 value들이 레코드를 따라가지 않는다. 덕분에 돌아버릴 뻔 했다
3. Antd의 Form에 Input Value의 변화 관리를 위임해라
HTML에서도 그랬지만 Antd의 Form 태그도 제출용 정보를 위한 문서 컨트롤러 역할을 수행한다. Antd는 Form 내부에 있는 element의 데이터를 관리하기 위한 많은 API를 제공하는데, 다행스럽게도 Form 태그를 이용하면 mobx 스토어의 변화를 스무스하게 감지 할 수 있었다.
문제 해결
Form 태그의 하위 Elem인 Form.Item 안쪽에 Input 태그를 넣고, Form.Item의 getValueFromEvent 메서드를 이용해서 이벤트의 타겟 value를 State로 계속 갱신해주었다. 이후, Input 태그에 포커스가 해지될 때 입력값을 서버로 업데이트 하는 메서드를 연결해주었더니....
- 유저 입력 값을 잘 받음
- sorter로 레코드 순서를 바꿔도 잘 따라감
- 입력이 끝날 때 마다 최신화 된 값으로 저장 잘됨
위 3가지 조건을 만족하는 훌륭한 기능이 탄생했다!
* 추가) 위 코드에는 name이 주석처리 되어있는데, 해당 부분을 지우니까 이상하게도 불러온 값을 Input에 넣지 못하고 있었다. 자세한 경위를 확인할 필요가 있다.
도움이 된 페이지들
https://soldonii.tistory.com/145
https://www.brainkart.com/article/Disadvantages-of-Using-DOM_8682/
'TIL' 카테고리의 다른 글
(21.12.28) What the hack is RSS?? (2) | 2021.12.28 |
---|---|
(21.12.02)chmod, Node_ENV (0) | 2021.12.03 |
(21.11.04) Node.js 요약 (0) | 2021.11.04 |
(21.10.27) TS] Type assertion에 관하여 (0) | 2021.10.28 |
(21.09.28) linter와 prettier 설정을 무시하는 방법 (0) | 2021.09.28 |