본문 바로가기
React/실험실

[React] 제어 컴포넌트 vs 비제어 컴포넌트

by 잉여개발자 2022. 11. 3.

앞서 useState와 useRef에 대해서 정리를 했었다. 

 

[React] useRef 그리고 useState

일반적으로 우리가 상태값을 관리할 때는 useState를 사용한다. 거기에서 state 값이 변경되면 리렌더링이 발생하면서 화면이 새롭게 그려진다. 그런데, 상태값이 변경되더라도 굳이 리렌더링이 필

bum-developer.tistory.com

해당 부분에 대한 보충 내용이지만 좀 더 개념적인 부분이라 따로 작성했다. 

 

제어 컴포넌트 

React에 의해서 값이 제어되는 컴포넌트를 말한다. 

우리가 자주 사용하는 useState를 사용해서 DOM 요소의 값을 관리하면 제어 컴포넌트이다. 

const App = () => [
    const [value, setValue] = useState("");
    
    const onChange = (e) => {
        setValue(e.currentTarget.value);
    }
    
    return <input value = {value} onChange={onChange} />
}

아주 익숙한 코드일 것이다. 

input의 값이 바뀌면 State의 값이 업데이트가 된다. 

 

React의 State에 의해서 input의 value가 결정되는데, 이것을 Single Source of Truth라고 한다. 

 

Single Source of Truth  ( 신뢰 가능한 단일 출처 )

신뢰 가능한 단일 출처란, 하나의 상태는 한 곳에서만 존재해야 한다는 뜻이다. 

 

우리가 React에서 State를 정의하고 여러 컴포넌트에서 해당 State를 사용해야 한다면 어떤 방식을

사용할까? 

 

Props, Context API, Redux, ModX ... 등등을 사용한다. 

 

이것을 사용하면 결국 상태를 여러개 만들어서 여러 곳에서 사용하는 것이 아닌 한 곳에서만 존재하고 

이것을 다른 컴포넌트가 가지고 와서 사용하게 된다. 

 

신뢰할 수 있는 데이터라는 뜻이다. 

 

<input value ={10}/>

다시 input으로 돌아와서 위 input 태그의 값은 10으로 다른 어디서도 변경되지 않는 

신뢰할 수 있는 데이터이다. 

 

<input id="age" value={10} />

let age = 0;

document.getElementById("age").addEventListener("input", (e) => {
    age = e.target.value;
})

input을 다른 곳에서도 사용하기 위해서 변수로 받아오는 코드를 작성했다. 

별 특별한 코드가 아닌 단순하게 입력값이 변경되면 age에 저장하는 코드이다. 

 

하지만 이것으로 input의 값을 가지고 올 때 출처가 2개가 되었다. 

input 자신의 value와 age 변수의 값으로 말이다. 

 

해당 프로젝트가 커지게 되면 age의 값이 input의 value만을 저장하는 상태로 확신할 수 있게 될까? 

어디선가 age의 값을 변경하게되면 최신 input의 값과 age의 값이 달라질 수 있다. 

 

이것을 React에서는 useState와 같은 상태로 보장해준다고 한다. 

const App = () => [
    const [value, setValue] = useState("");
    
    const onChange = (e) => {
        setValue(e.currentTarget.value);
    }
    
    return <input value = {value} onChange={onChange} />
}

예시의 코드를 다시 가져오면 input의 value를 가져오기 위해서 value라는 State를 사용했다. 

 

이때, 만약 다른 곳에서 state value가 변경된다면 변경된 value가 input에도 들어가기 때문에 

항상 최신 값으로 일치함이 보장된다. 

 

정리하면 useState를 사용해서 state의 값이 변경되더라도 input의 value에도 변경된 값이 들어가기

때문에 항상 최신의 값을 유지시켜주는 제어 컴포넌트가 된다. 

 

단점 

제어 컴포넌트를 State를 사용하기 때문에 불필요한 리렌더링이나, API를 호출할 수 있다. 

이것을 해결하기 위해서 쓰로틀링(Throttling)과 디바운싱(Debouncing)이 있다. 

 

쓰로틀링 

마지막으로 함수가 호출되면 일정시간이 지나기 전에는 다시 동일한 함수가 호출되지 않는 것을 말한다. 

 

디바운싱 

연이어 함수가 호출되면 가장 마지막 ( 또는 맨 처음 ) 함수만 호출되는 것을 말한다. 

 

언제 사용하는 것이 좋을까? 

입력 받은 값을 바로바로 유효성 검사를 해야하는 경우 사용하거나, 

실시간으로 인풋 값을 검사해야 하는 경우, 마지막으로 조건에 따라 버튼이 활성화 되야 하는 경우가 있다.

 

비제어 컴포넌트 

React에서 값을 보장하지 않는 방식을 말한다. 

useRef를 사용해서 값을 관리하는 방식을 비제어 컴포넌트라고 한다. 

const App = () => {
    const inputRef = useRef(null);
    
    return <input ref={inputRef} />
}

State로 값을 관리하지 않기 때문에 입력할 때마다 리렌더링, API가 호출되지 않아서 성능상 이점이 있다. 

그리고 특정한 작업을 해야한다면, ref를 통해서 접근해 value를 얻을 수 있다. 

 

 

결론

useState와 useRef에서도 말했지만 무조건 한가지 방식이 좋을 것이 아닌 필요에 따라

제어 컴포넌트나 비제어 컴포넌트를 사용하는 것이 중요하다.

반응형

댓글