오늘은 useEffect와 useRef는 리렌더링 동작을 제어하는 역할을 하는 훅인데 어떤 상황에서 써야 하는지 자세히 알아봤습니다.
useEffect
useEffect 훅은 함수 컴포넌트에서 사이드 이펙트를 수행하기 위해 사용됩니다.
사용 하는 경우
- 데이터 페칭: 컴포넌트가 마운트 될 때 서버로부터 데이터를 가져오는 경우
- 구독/해제: 웹 소켓이나 이벤트 리스너를 설정하고 정리하는 경우
- DOM 업데이트: 특정 DOM 요소의 속성을 직접 변경하는 경우
- 타이머 설정: setTimeout, setInterval과 같이 타이머를 설정하는 경우
useEffect는 컴포넌트가 마운트 될 때와 의존성 배열에 있는 값이 변경될 때 마다 실행되고 클린업 함수가 포함되어 있는 경우 컴포넌트가 언마운트 되거나 의존성이 변경되기 전에 실행됩니다
예시
import React, { useState, useEffect } from 'react';
function ExampleComponent() {
const [count, setCount] = useState(0);
const [text, setText] = useState('');
useEffect(() => {
console.log('Count has changed:', count);
// 클린업 함수
return () => {
console.log('Cleaning up...');
};
}, [count]);
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<input
value={text}
onChange={(e) => setText(e.target.value)}
/>
</div>
);
}
useEffect는 다음과 같은 상황에 실행 됩니다.
- 컴포넌트 마운트 시: 처음으로 컴포넌트가 화면에 렌더링 될 때
- count값이 변경될 때: 버튼을 클릭해서 count 값을 증가시킬 때
클린업 함수는 count 값이 변경되어 useEffect가 다시 실행되기 전에 이전 효과를 정리하는 용도로 사용됩니다.
다른 예시
// 의존성 배열이 없는 경우
useEffect(() => {
console.log('렌더링 될 때마다 계속 실행됩니다.');
});
// 빈 의존성 배열
useEffect(() => {
console.log('오직 처음에 렌더링 된 이후 한 번만 실행됩니다.');
return () => {
console.log('컴포넌트가 언마운트 될 때 한 번만 실행됩니다.');
};
}, []);
// 여러 의존성
useEffect(() => {
console.log('둘 중 하나라도 변경되면 실행 됩니다', count, text);
}, [count, text]);
useRef
useRef 훅은 컴포넌트 생애 주기 전반에 걸쳐 유지되는 변경 가능한 참조를 제공하기 위해 사용됩니다.
사용하는 경우
- DOM 요소 접근: 특정 DOM 요소에 직접 접근해야 할 때
- 값 유지: 렌더링 간에 값이 유지되어야 하지만, 해당 값이 변경될 때 리렌더링이 필요 업슨 경우
- 타이머 저장: setTimeout이나 setInterval의 ID를 저장하는 경우
useRef는 리렌더링을 트리거하지 않고 current 프로퍼티를 통해 값을 저장하고 접근할 수 있습니다.
useRef의 current 프로퍼티는 상태가 변경되어도 컴포넌트가 리렌더링되지 않기 때문에 성능 최적화에 유리합니다
예시
// DOM 요소 접근하기
import React, { useRef } from 'react';
function FocusInput() {
const inputRef = useRef(null);
const handleClick = () => {
inputRef.current.focus();
};
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={handleClick}>Focus the input</button>
</div>
);
}
useRef를 사용하여 입력 필드에 대한 참조를 생성하고, 버튼 클릭 시 해당 입력 필드에 포커스를 줍니다.
// 컴포넌트의 이전 값 저장하기
import React, { useState, useEffect, useRef } from 'react';
function PreviousValueExample() {
const [count, setCount] = useState(0);
const prevCountRef = useRef();
useEffect(() => {
prevCountRef.current = count;
}, [count]);
const prevCount = prevCountRef.current;
return (
<div>
<p>Current Count: {count}</p>
<p>Previous Count: {prevCount}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
useRef와 useEffect를 사용하여 이전 count 값을 저장하고, 이를 현재 값과 비교할 수 있습니다.
// 데이터 유지하기
import React, { useRef } from 'react';
function FormComponent() {
const formDataRef = useRef({
name: '',
email: ''
});
const handleChange = (e) => {
formDataRef.current[e.target.name] = e.target.value;
};
const handleSubmit = () => {
console.log(formDataRef.current);
};
return (
<div>
<input name="name" onChange={handleChange} />
<input name="email" onChange={handleChange} />
<button onClick={handleSubmit}>Submit</button>
</div>
);
}
useRef를 사용하여 폼 데이터를 유지할 수 있습니다. 리렌더링 조건 중 State를 사용하지 않아서 입력 값이 변경될 때마다 컴포넌트가 리렌더링되지 않습니다.
요약 - useEffect와 useRef가 사용 하는 경우
useEffect
- 사이드 이펙트를 수행해야 하는 경우 (데이터 페칭, 이벤트 리스너 설정, 타이머 설정)
- 컴포넌트가 마운트될 때나 의존성이 변경 될 때 특정 작업을 수행해야 하는 경우
- 컴포넌트가 언마운트될 때 클린업 작업이 필요한 경우
useRef
- 렌더링 간에 값을 유지하지만, 해당 값이 변경될 때 리렌더링이 필요하지 않을 경우
- DOM 요소에 직접 접근해야 하는 경우
- 타이머 ID와 같은 참조를 저장해야 하는 경우
결론
특정 작업이 컴포넌트의 생애주기와 관련된 경우 useEffect를 사용하고 리렌더링과 무관하게 DOM에 접근할 필요가 있는 경우에 useRef를 사용합니다.
'TIL' 카테고리의 다른 글
TIL - 리액트로 가계부 만들기 - 2 (0) | 2024.05.22 |
---|---|
TIL - 리액트로 가계부 만들기 - 1 (0) | 2024.05.21 |
TIL - 리액트 컴포넌트 파일 구조 및 상태 업데이트 방식 개선 (0) | 2024.05.17 |
TIL - 이벤트 핸들러 연습 (0) | 2024.05.16 |
TIL - 리액트로 투두리스트 만들면서 느낀 리액트의 장점 (1) | 2024.05.14 |