오늘의 나는 무엇을 배웠을까?
React 공식 문서에 따르면, React에 의해 값이 제어되는 폼 엘리먼트를 "제어 컴포넌트" 그렇지 않은 엘리먼트를 "비제어 컴포넌트" 라고 부른다고 한다.
근데 사실 이게 무슨 의미인지 와닿지 않는다. 조금 더 쉬운 이해를 위해 아래에 각각 정리를 해보려 한다.
input
태그의 value
속성을 지정하고 사용한다.
이 때 value
의 값이 State
인지 Prop
인지는 중요하지 않다.
function App() {
const [input, setInput] = useState("");
const handleChange = (e) => {
setInput(e.target.value);
}
return (
<form>
<input value={input} onChange={handleChange} />
<form>
);
}
위 코드는 input
의 값이 변경될 때마다 handleChange
함수를 통해 state
값을 업데이트 해 주는 제어 컴포넌트이다.
input
의 value는 항상 컴포넌트의 input state
와 일치하게 되고, 이에 따라 사용자가 입력한 값과 리액트에서 사용하는 값이 실시간으로 동기화된다. 따라서 제어 컴포넌트의 value는 항상 최신값을 유지한다.
또한, 제어 컴포넌트는 사용자가 입력을 할 때마다 리렌더링을 하게 된다.
물론 항상 제어 컴포넌트를 사용해야 하는 것은 아니므로, 상황에 맞게 잘 사용해 보자.
앞서 제어 컴포넌트의 경우 입력이 발생할 때마다 state가 갱신되기 때문에 불필요한 리렌더링, 또는 API 요청을 하게 되고 자원 낭비 문제가 생길 수 있다.
이를 해결하기 위해서,
의 방법을 활용할 수 있다.
input
의 value
속성을 리액트에서 지정하지 않는 컴포넌트이다.
function App() {
const [input, setInput] = useState("");
const handleChange = (e) => {
setInput(e.target.value);
}
return (
<form>
<input onChange={handleChange} />
<form>
);
}
제어 컴포넌트의 코드와 비교했을 때 input
태그의 value값을 따로 관리하지 않는 차이를 볼 수 있다. 이 때 리액트에서 사용하는 값과 실제 input
값에 차이가 생긴다.
제어 컴포넌트와는 다르게 비제어 컴포넌트는 사용자가 버튼을 클릭하는 행위와 같이 직접 트리거 하기 전까지 리렌더링을 발생시키지 않으며 사용자의 입력값과 리액트에서 사용하는 값을 동기화시키지 않는다.
HTML 엘리먼트에 대해 ref
를 props
로 넘겨 주어 DOM 엘리먼트를 담거나, 콜백 함수를 넘겨 주어 DOM 엘리먼트를 매개변수로 접근할 수 있다.
useRef
함수로 Ref 객체를 만들 수 있다.
import { useRef } from "react";
// ~~
const ref = useRef();
ref
prop에 만들어진 Ref 객체를 내려준다
<input ref={ref} ~~ />
Ref 객체의 current
프로퍼티를 사용하여 DOM 노드를 참조한다.
const node = ref.current;
DOM 노드의 경우 렌더링이 끝나야 생기기 때문에 ref 객체의 current 프로퍼티 값은 컴포넌트가 화면에 렌더링 되었을 때만 존재한다.
따라서, current
프로퍼티 값이 존재하는지 검사하고 사용해야 한다.
if (node) {
//node 사용 코드
}
함수 내부에서 함수 밖의 값이나 상태를 변경하는 것
리액트에서 useEffect
함수는 컴포넌트 함수 내에서 사이드 이펙트를 실행하고 싶을때 사용하는 것이다. 즉, 리액트 외부에 있는 데이터나 상태를 변경할 때 사용한다.
e.g. DOM 노드 직접 변경, 브라우저에 데이터 저장, 네트워크 리퀘스트
그렇다면 핸들러 함수를 사용할 수도 있고 useEffect
를 사용할 수 있는 경우에는 어떤 것을 선택해야 할까?
따로, 언제 써야 하는지 정해져 있지는 않지만 컴포넌트 안의 데이터와 리액트 밖의 데이터를 일치시키는 '동기화' 에 사용하면 유용하다.
useEffect
의 콜백에서 사이드 이펙트를 만들었을 때 정리가 필요한 경우가 있다. 이 때 콜백 함수에서 반환 값으로 정리하는 함수를 반환해 주면 사이드 이펙트에 대한 뒷정리가 가능하다.
정리 함수는 콜백 실행과 1:1로 대응되어 콜백 한 번 실행 시 반드시 한 번 실행된다. 새로운 콜백 함수가 호출되기 전 (앞에서 실행한 콜백의 사이드 이펙트 정리) 이나 컴포넌트가 화면에서 사라지기 전 (가장 마지막으로 실행된 콜백의 사이드 이펙트 정리) 에 실행된다.
내일의 나는 무엇을 해야할까?