리액트를 개발하다 프로젝트에서 그룹생성 기능을 맡고 기능 개발을 하였습니다. 서버에서 get 해온 데이터를 렌더링하고 유저가 input 데이터를 입력하고 Form 제출을 서버에 put 요청을 보내는 작업이 많았었는데요.
저는 너무나 당연하게도 제어 컴포넌트(controlled)를 사용했습니다. 물론 input 태그가 엄청나게 많지는 않아서 이슈는 없었지만 리렌더링 관련된 생각이 나서 글을 정리하게 되었습니다.
제어,비제어 컴포넌트를 설명하기 앞서 Form Tage ELements를 설명하겠습니다.
대표적인 input,textarea,select 태그들이 있습니다. 사용자가 입력한 값에 대해서 그 값을 가쟈올 수 있는데 value Attribute 를 통해 값에 접근할 수 있습니다.
신뢰 가능한 단일 출처란 하나의 상태는 한곳에만 있어야 한다.라는 뜻입니다.
input 을 보면 DOM 에 있는 Value Attribute 를 실시간으로 보여줍니다.
코드를 보시면 지금 변수 Variable 그리고 Value Attribute 2가지를 볼 수 있습니다. 이 코드를 그림으로 표현해보면 다음과 같습니다.
현재 Input에서 2개의 Varibale 과 Value Attribute를 받고 있는것을 볼 수 있습니다.
Value Attribute 가 계속 최신화가 되고 그 값을 Varibale 갖고 있습니다.
만약 A컴포넌트는 Value Attribute 가 갖고있고, B컴포넌트는 Varibale가 갖고 있다고 가정합니다.
만약 동료 개발자가 실수로 인해 변수 코드를 지운다면 Varibale로 선언된 변수는 갱신되지 못하게 됩니다.
상태는 하나였지만 두가지 출처로 인해 이러한 차이점이 발생할 수 있기 떄문에 신뢰 가능한 단일 출처를 받는것이 중요합니다.
제어 컴포넌트
이에 React는 제어 컴포넌트를 통해서 문제를 해결할 수 있습니다. 대표적인 예시를 코드를 보여드리겠습니다.
Value Attribute와 state를 결합하여 name State를 신뢰 가능한 단일 출처로 만든 사진입니다.
따라서 제어 컴포넌트는 Form의 사용자 입력값을 React가 제어한다고 보면 되겠습니다.
비제어 컴포넌트
비제어 컴포넌트는 다음과 같은 코드블록이 대표적인 예시입니다.
state와 달리 useRef
를 사용해준 모습입니다. Ref 같은 경우엔 순수 자바스크립트 객체이기 때문에 input
태그에 직접 접근할 수 있고, 값이 변하더라도 리렌더링이 발생하지 않는 것을 볼 수 있습니다.
따라서 비제어 컴포넌트는 React가 Form의 입력값을 제어하지 않습니다. Value Attribute가 신뢰 가능한 단일 출처를 갖고 있다고 보면 되겠습니다.
컴포넌트 분리를 잘 해주면 리렌더링 이슈가 없는지도 모르겠습니다. 하지만 유저가 많은 데이터를 수정했을 때, 데이터들을 한 데 모아 서버에 한번에 보내기 위해서는 각 value
값을 input
태그들의 부모 컴포넌트에서 관리하게 됩니다. 이 경우 하나의 input
태그의 데이터를 변경하기만 해도 부모 컴포넌트가 갖고 있는 모든 태그가 리렌더링이 됩니다.
input
태그가 몇 개 되지 않는 경우 리렌더링이 오래 걸리지 않기 때문에 문제가 되지는 않습니다. 하지만 부모 컴포넌트가 갖고 있는 자식 컴포넌트(input태그)가 수백개가 될 경우 리렌더링이 상당히 오래 걸리게 됩니다. 이 경우에는 UX가 당연히 좋게 보이지 않을 수 밖에 없습니다.
비제어 컴포넌트를 사용할 경우 위에서 설명했듯이 DOM에게 직접적으로 맡기게 됩니다. 유저가 입력한 값의 동기화는 이뤄지지 않는다는 이야기죠. 대신 리렌더링을 거치지 않고 유저의 입력 값을 화면에 빠르게 보여줄 수 있게 됩니다.
관리하고 있는 프로젝트에 유저 수가 많다고 가정하고!! 수정 버튼을 눌러 변경 사항을 서버에 보내야 할 경우에 useRef
를 활용하여 input
태그의 값들을 불러올 수 있습니다.
리액트 공식문서에서는 모든 상황에서 제어 컴포넌트를 사용할 것을 권장합니다. 하지만 특별한 케이스에서는 비제어 컴포넌트를 사용할 수도 있다고 합니다.
제어 컴포넌트를 사용하면 input
값이 항상 동기화 되어있기 때문에 서버에 요청을 보낼 떄 따로 useRef
를 사용해서 값을 불러올 팔요가 없습니다. 또한 이메일,비밀번호 형식 등을 input
값의 매 변경때마다 유효성 검사를 하고 싶다면 매번 동기화되는 제어 컴폰넌트를 사용하는게 훨씬 수월 할 수 있습니다.
개인적으로 만약 내 프로젝트에서 부모 컴포넌트에서 관리해야하는 input,textarea,select
태그가 많고, 수많은 데이터를 한번에 수정해야 한다는 상황이 온다면 UX가 조금 더 수월한 비제어 컴포넌트를 사용하는 것이 더 좋다고 생각합니다.