react에서 제어 컴포넌트, 비제어 컴포넌트를 고려하여 form을 다루어야 하는 경우가 있었다.
제어 컴포넌트, 비제어 컴포넌트에 대한 개념이 없었고
이전에 formik을 다루었었던 경험이 있어서 습관적으로 제어 컴포넌트 형식으로 구현을 했었다.
그래서 제어, 비제어 컴포넌트에 대해 알아보려고 한다.
제어 컴포넌트
값이 바뀔때마다 매번 렌더링을 하게 된다.
(좀 더 React스럽다 라고 언급이 되는것 같다)
코드의 내용을 보면 useState를 통해 상태값 하나를 추가해주었고
이는 Input의 value값이 된다.
input의 onChnage 핸들러를 추가하여 input 입력값이 변경될때마다 상태를 업데이트 해주었다.
상태가 업데이트 되었으므로 렌더링이 일어난다.
매번 상태를 업데이트 해주므로 화면에 보이는 값과 컴포넌트가 관리하는 상태의 값이 일치한다.
따라서 다음과 같은 경우 유용하게 사용할 수 있다.
- input값의 즉각적인 유효성 검사 실행
- 폼 제출전에 적합하지 않은 값이 있을 경우 버튼을 비활성화 할수 있다.
- 특정 입력 형태를 강제할수 있다(신용카드 번호같이)
이러한 것들과 유사한 경우가 아니라면 비제어 컴포넌트를 택하는 것도 좋은 선택일수 있지 않을까??
import { useState, useRef } from 'react';
const ControlledUnit = () => {
const [inputValue, setInputValue] = useState('');
const renderRef = useRef(0);
renderRef.current += 1;
const inputHandler = (e) => {
const value = e.target.value;
console.log(value);
setInputValue(value);
}
return (
<div className="controlled-wrapper">
<div className="title">제어 컴포넌트</div>
<div className="render-count">렌더링 횟수: {renderRef.current}</div>
<input value={inputValue} onChange={inputHandler} />
<button onClick={inputHandler}>클릭</button>
</div>
);
}
export default ControlledUnit;
비제어 컴포넌트
바닐라 자바스크립트로 form을 구현할때와 크게 다르지 않다.
input의 값을 매번 추적하지 않아 state가 변경되더라도 rendering 되지 않는다(아래의 영상 참고)
값이 필요할때 가져와서 사용해야 한다.
예를 들면 form이 제출될 시에는 입력받은 값을 가져와야 한다.
이럴때는 form submit에 handler를 추가하여 ref의 current value 값을 넣어주면 될것이다.
여러개의 input들이라면 여러개의 ref가 필요할 것이다.
불필요 할수도 있는 렌더링을 시키지 않는 점에서와 코드가 좀 더 깔끔해 질 수 있다는 장점을 가지고 있다고 생각한다.
import { useState, useRef } from 'react';
const UnControlledUnit = () => {
const renderRef = useRef(0);
renderRef.current += 1;
const inputRef = useRef(null);
const inputHandler = () => {
console.log(inputRef.current.value);
}
return (
<div className="uncontrolled-wrapper">
<div className="title">비제어 컴포넌트</div>
<div className="render-count">렌더링 횟수: {renderRef.current}</div>
<input ref={inputRef} />
<button onClick={inputHandler}>클릭</button>
</div>
);
};
export default UnControlledUnit;
위에서 언급한 제어컴포넌트를 사용하는 경우도 input의 pattern, setCustomValidity 등 다양한 도구들을 통해 어느정도 선까지는 쫒아갈 수 있지 않을까 생각한다. 이 부분은 본인의 역량!!!
비제어 컴포넌트의 경우 UseRef를 쓰는 이유에 대해 잘 정리된 글이 있어 인용하였다
1. useRef()는 heap영역에 저장되는 자바스크립트 객체
2. 렌더링 할때마다 동일한 객체를 제공해준다. heap에 저장을 하므로 어플리케이션이 종료되거나 가비지 컬렉팅이 되기 전까지, 참조시에는 같은 메모리 값을 가진다.
3. 값이 변경되어도 리렌더링 되지 않는다. 같은 메모리 값을 항상 반환하므로 변경사항을 감지할 수가 없어서 리렌더링을 하지 않는다.
결론
리액트 공식문서에는 아래와 같이 언급하고 있다.
대부분 경우에 폼을 구현하는데 제어 컴포넌트를 사용하는 것이 좋습니다. 제어 컴포넌트에서 폼 데이터는 React 컴포넌트에서 다루어 집니다. 대안이 비제어 컴포넌트는 DOM 자체에서 폼 데이터가 다루어집니다.
제어 컴포넌트의 사용경우인 유효성 검사, 버튼 비활성화, 특정 입력 강제 등이 사용성 측면에서 더 선호되기에 위와 같이 언급되어있는게 아닐까 조심스레 추측해본다.
둘 중에 정답은 없고 상황에 따라 알맞은 선택을 개발자가 해야하지 않을까 생각이 든다.
* 폼을 다룰때 react-hook-form, formik 과 같은 라이브러리를 사용할 수 있다.
formik은 제어 컴포넌트 기반이고 react 공식문서에서도 추천하고 있다. 코드량이 꽤나 많아 지지만 우용한 도구임에는 틀림없다.
react-hook-form은 기존의 라이브러리들보다 훨씬 적은 렌더링을 시키는 것을 장점으로 어필하고 있다.
최근 트렌드를 보니 react-hook-form이 무섭게 치고 올라오고 있다.
한번 사용해봐야 겠다!
https://ko.reactjs.org/docs/forms.html#controlled-components
https://goshacmd.com/controlled-vs-uncontrolled-inputs-react/#conclusion
'Frontend > React' 카테고리의 다른 글
React 피드백 내용 정리 (0) | 2022.03.04 |
---|---|
React useLayoutEffect (0) | 2022.03.03 |
React twice render (0) | 2022.02.24 |
cra + typescript + jest (0) | 2022.02.23 |
넘블챌린지 [Square Select Game] (0) | 2022.02.10 |