useEffect & useRef
useEffect
컴포넌트에서 부수 효과(Side Effects)를 처리할 때 사용되는 Hook
- Side Effects 관리
API 호출, 타이머 설정, 구독(subscription)등의 작업을 처리할 때 사용
React의 렌더링 흐름과 독립적으로 실행됨 - 컴포넌트 생명주기 관리(라이프사이클 제어 가능)
클래스형 컴포넌트의 componentDidMount, componentDidUpdate, componentWillUnmount를 대체
특정 시점(마운트, 업데이트, 언마운트)에서 실행되는 코드를 넣을 수 있음 - 의존성 배열을 활용한 조건부 실행
특정 상태 값이 변경될 때만 실행되도록 제어 가능
useEffect 기본 문법
useEffect(() => {
console.log("컴포넌트가 마운트 또는 업데이트됨");
return () => {
console.log("컴포넌트가 언마운트됨");
};
}, [/* 의존성 배열 */]);
라이프사이클 단계별 실행
Mount (처음 렌더링 시 실행)
useEffect(() => {
console.log("컴포넌트가 마운트됨");
}, []); // 빈 배열이면 한 번만 실행됨
componentDidMount → useEffect(() => {}, [])
Update (특정 상태가 변경될 때 실행)
useEffect(() => {
console.log("firstName이 변경됨:", firstName);
}, [firstName]); // firstName이 변경될 때 실행됨
componentDidUpdate → useEffect(() => {}, [의존성])
Unmount (컴포넌트가 사라질 때 실행)
useEffect(() => {
return () => {
console.log("컴포넌트가 언마운트됨");
};
}, []);
componentWillUnmount → useEffect(() => { return () => {}; }, [])
의존성 배열을 활용한 실행 조건
의존성 배열실행 조건
[] (빈 배열) | 마운트될 때 한 번 실행 |
[firstName] | firstName이 변경될 때마다 실행 |
없음 | 컴포넌트가 렌더링될 때마다 실행 |
*useEffect가 두 번 실행되는 문제
React의 StrictMode가 활성화된 경우(Indes.jsx) 개발 모드에서 일부 Hook이 두 번 실행될 수 있음
해결 방법: index.js에서 <React.StrictMode>를 제거
useRef
DOM 요소에 직접 접근하거나, 값이 변경되어도 리렌더링을 발생시키지 않는 변수를 저장할 때 사용
- DOM 요소에 직접 접근
ref 속성을 이용해 특정 요소를 제어할 수 있음 - 렌더링 없이 값 유지
useState와 달리, 값이 변경되어도 렌더링이 발생하지 않음 - 이전 값 저장
useRef를 이용해 이전 상태 값을 추적할 수 있음
useRef 기본 문법
const inputRef = useRef(null);
<input ref={inputRef} />;
- inputRef.current를 통해 실제 DOM 요소에 접근 가능
- .focus(), .value 등을 활용하여 직접 조작할 수 있음
useRef vs. useState
기능 | useRef | useState |
렌더링 발생 여부 | X | O |
DOM 직접 접근 | 가능 | 불가능 |
값 유지 | 가능 | 가능 |
useRef 활용 예
1. 입력창에 포커스 자동 맞추기
function InputFocus() {
const inputRef = useRef();
useEffect(() => {
inputRef.current.focus(); // 마운트될 때 자동으로 포커스
}, []);
return <input ref={inputRef} placeholder="자동 포커스" />;
}
2. 이전 값 저장
function PreviousValue() {
const [count, setCount] = useState(0);
const prevCountRef = useRef();
useEffect(() => {
prevCountRef.current = count;
}, [count]);
return (
<div>
<p>현재 값: {count}</p>
<p>이전 값: {prevCountRef.current}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
최종 코드
import React, { useState, useRef, useEffect } from "react";
// 컴포넌트 생명주기
// 1. DOM이 마운트됨 (Mount)
// 2. 상태가 변경됨 (Update)
// 3. DOM이 언마운트됨 (UnMount)
function App() {
const [formData, setFormData] = useState({
firstName: "",
userAlias: "",
});
const firstNameInputRef = useRef();
const { firstName, userAlias } = formData;
useEffect(() => {
console.log(`First Name Updated: ${firstName}`);
return () => {
console.log("unmounted");
};
}, [firstName]);
const handleInputChange = (e) => {
const { value, name } = e.target;
setFormData({
...formData,
[name]: value,
});
};
const handleReset = () => {
setFormData({
firstName: "",
userAlias: "",
});
firstNameInputRef.current.focus();
};
return (
<div>
<input
name="firstName"
placeholder="First Name"
onChange={handleInputChange}
value={firstName}
ref={firstNameInputRef}
/>
<input
name="userAlias"
placeholder="Alias"
onChange={handleInputChange}
value={userAlias}
/>
<button onClick={handleReset}>Reset</button>
<div>
<strong>Values: </strong>
{firstName} ({userAlias})
</div>
</div>
);
}
export default App;
'React > ReactThreeFiber' 카테고리의 다른 글
3D 오브젝트 불러오기 (0) | 2025.03.14 |
---|---|
useContext (0) | 2025.03.14 |
React로 사고하기 (1) | 2025.03.13 |
Component (0) | 2025.03.12 |
Event Handling (0) | 2025.03.12 |