React _ Controlled Component

kyle kwon·2022년 10월 26일
0

React

목록 보기
3/15
post-thumbnail

Prologue

우리는 로그인 또는 회원가입 같은 동작을 할 때, 사용자의 데이터를 받아 어디론가 제출하는 Form 요소를 종종 사용하곤 합니다. Html form 요소는 자체 내부 상태를 가져, React의 다른 DOM 요소들과는 다르게 동작합니다. 하지만, 리액트에서 Html form 요소와 같이 똑같이 동작하게 하고 싶다면, 그대로 사용하면 된다고 공식 문서에서 언급하고 있습니다.


HTML 마크업을 살펴보겠습니다.

<form>
  <label>ID</label>
  <input type="text" name="id"/>
  <label>PassWord</label>
  <input type="text" name="pw" placeholder="Enter your password"/>
  <button>submit</button>
</form>

위와 같이 form이라는 요소 내부에 input 요소 2개와 button이 담겨 있는데, 정보를 입력하고 버튼을 클릭(제출)하면 새로운 페이지로 이동하는 기본 Form 동작을 알 수 있습니다. form 요소 내부에 button이 담겨 있다면, submit 타입으로 생각하여 자체 내부 동작을 수행할 것입니다.
React에서도 return 문 안에서 동일하게 Form 요소를 작성한다면 동일하게 동작할 것입니다.

이 기본적인 동작을 막아주는 메서드로는 event.preventDefault()가 있습니다.

일반적인 경우 동적으로 데이터를 변경하거나 수정하는 작업은 자바스크립트에서 컨트롤하는 것이 좋은데요. form의 제출을 처리하고, form에 입력한 데이터에 접근하도록 하는 것이 좋습니다. 이와 같은 방식을 제어 컴포넌트 라고 불리는 기술을 이용하는 것입니다.




Controlled Component

form 요소를 렌더링하는 React 컴포넌트는 form에서 발생하는 사용자의 입력값을 제어합니다.
코드를 보면서, 어떻게 제어하고 있는 지 확인해 보겠습니다.

const [input, setInput] = useState('');

const handleChange = (e) => {
	setInput(e.target.value);
}

return (
 <>
    <input value={input} type="text" name="id" onChange={handleChange}/>
 </>
)

input 요소 내에서 사용자의 입력값을 컨트롤 하기 위해, value라는 attribute에 jsx 문법으로 state 값인 input을 담았습니다. 이벤트 리스너 onChange를 통해, 내부 입력값 변동이 감지되면 handleChange 함수를 호출해, 내부적으로는 input이라는 상태값을 변경시키는 setInput이라는 setState 함수를 실행합니다.

이렇게 React로 state라는 Single Source of Truth를 이용해 값이 제어되는 form 엘레먼트를 제어 컴포넌트라고 합니다.




Multiple Inputs

위에서는 input태그가 하나일 때 제어 컴포넌트가 어떻게 동작하는지 살펴보았습니다. 만약, input 태그가 2개 이상일 경우에는 어떻게 제어할 수 있을까요?

01   input.name

먼저, input 태그의 name이라는 속성을 활용하는 방법입니다.
코드를 바로 살펴 보겠습니다.

const [inputId, setInputId] = useState('');
const [inputPw, setInputPw] = useState('');

const handleChange = (e) => {
	if(e.target.name === 'id'){
     	setInputId(e.target.value);
    } else if(e.target.name === 'pw'){
     	setInputPw(e.target.value); 
    }
}

return (
 <>
    <input value={inputId} type="text" name="id" onChange={handleChange}/>
    <input value={inputPw} type="text" name="pw" onChange={handleChange}/>
 </>
)

위와 같은 방법은 2~3개의 input을 다룰 때까지는 괜찮으나, input이외에 textarea, select와 같은 form 요소와 관련된 DOM 요소들이 늘어나면, 위의 handleChange 함수 내부의 조건문의 분기도 증가할 뿐만 아니라, 다뤄야할 state(상태)도 많아져, 효율적이지 않습니다.

다음과 같이 form 요소가 많아지면, 다음과 같이 처리할 수 있습니다.


02   Destructuring & Computed Property Syntax

위에서 컨트롤 할 상태값이 많아지는 문제가 생긴다고 하였습니다. 다음과 같은 상황을 해결하는 방법으로는, state의 초기값에 primitive value(원시값)이 아닌 객체를 담는 것입니다.

백문이 불여일견입니다. 코드를 살펴보겠습니다.

const [userInputs, setUserInputs] = useState({
  id: '',
  pw: ''
});

const handleChange = (e) => {
  setInput({...input, [e.target.name] = e.target.value});
}

const handleSubmit = (e) => {
 	e.preventDefault();
  	alert(`ID:${e.target.id} | PW: ${e.target.pw} is approved`);
}

return (
  <form onSubmit={handleSubmit}>
  	<input value={userInputs.id} type="text" name="id"/>
  	<input value={userInputs.pw} type="text" name="pw"/>
    <input type="submit"/>
  </form>
  )

state 값을 01 번의 경우처럼 여러 개로 나눌 필요없이 객체에 한 번에 담아, destructuring 문법과 computed property 문법을 활용하면, 한 번에 효율적으로 관리할 수 있습니다.




Conclusion

이번에는 React에서 form 요소를 다루는 제어 컴포넌트에 대해서 알아 보았습니다.
제어 컴포넌트의 대안으로 개념인 비제어 컴포넌트라는 방식도 존재하는데요. useRef라는 hook을 사용하면, state의 상태 변경이 발생될 때마다 무조건적으로 리렌더링 되는 동작을 막아, 조금 더 효율적으로 일종의 상태를 관리할 수 있습니다.

다음에는 비제어 컴포넌트에 대해서 정리해보는 시간을 가져보겠습니다.

profile
FrontEnd Developer - 현재 블로그를 kyledot.netlify.app으로 이전하였습니다.

0개의 댓글