트러블슈팅 : MuiOutlinedInputInput contains an input of type text with both value and defaultValue props.
DOK 프로젝트를 진행하면서 MUI를 사용하였는데, 아무래도 처음 쓰다보니 예시 코드를 가져와서 값을 변경하는 방식을 많이 사용하였다.
그러다보면 가끔 위와 같은 에러가 떴다.
대충 text 타입의 input에서 controlled와 uncontrolled가 같이 사용되고 있다는 말인 것 같은데 controlled와 uncontrolled는 처음 들어봐서 찾아보니 그동안 react에서 뭔가 께름직 했던 input 사용 방식과 연관이 있었다.
Controlled & Uncontrolled
우선 Form 요소에는 input, textarea, select가 있다. 이 요소들은 단순하게 HTML에서 사용할 수 있고, 브라우저에 있는 입력 창에 의해 사용자 입력 값으로 업데이트 된다.
즉, HTML 요소 스스로 State를 관리한다는 뜻이다.
하지만 리액트에서 form 요소들을 사용하려고 하면 우리는 일반적으로 useState를 사용하여 input의 상태를 관리할 것이다.
그렇게 되면 React 컴포넌트에서도 State를 가지고, HTML form 요소에서도 State를 가지게 되어 "single source of truth" 원칙을 위배하게 된다.
때문에 State 를 둘 중 하나로 사용하여 위배된 원칙을 해소해야 한다.
이 때 React State를 선택하여 사용하는 것을 "controlled components" 라고 부르고,
반대로 HTML State 를 사용하는 것을 "uncontrolled componentns" 라고 한다.
예를 들어 controlled 방식은 다음과 같이 useState로 input의 value를 관리하고, onChange를 사용하여 setState로 value를 업데이트 한다.
const ControlledExample = () => {
const [val, setVal] = useState("");
const handleChange = (e) => {
setVal(e.target.value);
};
return (
<form>
<input type={"text"} value={val} onChange={handleChange} />
</form>
);
}
uncontrolled 방식은 HTML State로 관리하기 때문에 state를 업데이트 하기 위한 작업이 필요 없다.
const UncontrolledExample = () => {
return (
<form>
<input type={"text"} defaultValue={val} name={"val"} />
</form>
);
}
두 방식을 비교했을 때,
controlled는 React의 state 관련 기능을 많이 사용할 수 있다.
하지만 form 요소가 늘어날수록 useState와 handler가 비례하여 늘어나고, 리랜더링이 state가 업데이트 할 때마다 일어난다는 단점이 있다.
반대로 uncontrolled는 코드도 훨씬 간단해지고 리랜더링에 영향을 받지도 않지만,
React 측면에서 React의 기능을 제대로 쓸 수 없다는 단점이 있다.
Warning이 뜬 이유
controlled 방식과 uncontrolled 방식은 React 자체에서 공식적으로 구분되어 있고, 앞서 말했듯이 "single source of truth" 원칙에 따라 한 가지 방식만 사용해야 한다.
즉, 두 방식을 같이 썼기 때문에 에러가 난 것이다.
실제 내 코드를 보면 value와 defaultValue를 같이 사용하였다.
defaultValue는 uncontrolled 방식에서 초기 값을 결정하기 위해 쓰이므로 uncontrolled를 사용한 것이고, onChange를 통해 value를 변경하고 있으므로 controlled 방식도 동시에 사용하고 있는 것이다.
이 내용을 몰랐을 때 MUI 예제에서 아무거나 가져와서 사용하다보니 defaultValue가 따라 들어왔고, 원래 사용하던 방식대로 value와 onChange를 사용하려다 보니 해당 에러가 생긴 것 같다.
나는 React State를 사용하여 상태관리를 해야 했기 때문에 defaultValue를 삭제하여 에러를 해결했다.
결론적으로 장단점이 있으니 상황에 따라 맞춰서 사용하면 되지만,
React 공식 문서에서도 Controlled 방식을 권장하고 있다.
연관 에러
내가 본 에러 외에 Warning: A component is changing an uncontrolled input to be controlled... 라는 에러도 있다.
이건 컴포넌트가 uncontrolled input에서 controlled input으로 변경하려고 한다... 라는 내용인데, controlled 방식으로 사용하는데 useState() 선언할 때 아무 값도 주지 않았을 때 나타나는 에러이다.
useState에 빈 값을 두면 초기값이 undefined가 되고 input에 undefined가 전달된다. 이 때 React는 undefined를 보고 input이 uncontrolled라고 생각하게 되고, 그 이후 setValue()를 통해 값이 바뀌게 되면 controlled 방식으로 변경하려고 한다고 생각하여 해당 에러가 뜨게 된다.
참고 자료
- https://mygumi.tistory.com/419 [마이구미의 HelloWorld:티스토리]