[React] useState와 useEffect 활용 예제
![[React] useState와 useEffect 활용 예제](/content/images/size/w1920/2025/01/react_png_logo-3.png)
React 개발을 하면서 useState와 useEffect를 언제 사용해야 하는지 고민했던 경험과 실전에서 활용 가능한 몇가지 예제들을 공유하고자 한다.
사용자 입력 관리
폼(Form) 데이터를 다룰 때 useState는 필수적이다.
function SignUpForm() {
const [formData, setFormData] = useState({
username: '',
email: '',
password: ''
});
const handleChange = (e) => {
setFormData({
...formData,
[e.target.name]: e.target.value
});
};
return (
<form>
<input
name="username"
value={formData.username}
onChange={handleChange}
/>
{/* 다른 입력 필드들... */}
</form>
);
}
토글 상태 관리
모달, 드롭다운, 메뉴 등의 UI 요소의 열림/닫힘 상태를 관리할 때 유용하다.
function Dropdown() {
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<button onClick={() => setIsOpen(!isOpen)}>
메뉴 {isOpen ? '닫기' : '열기'}
</button>
{isOpen && (
<ul>
<li>메뉴 1</li>
<li>메뉴 2</li>
</ul>
)}
</div>
);
}
로딩 상태 관리
function ProductList() {
const [products, setProducts] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
// ...fetch 로직
}
브라우저 이벤트 리스너 관리
스크롤 위치 감지나 화면 크기 변경 감지 등에 활용한다.
function ScrollIndicator() {
const [scrollPercentage, setScrollPercentage] = useState(0);
useEffect(() => {
const handleScroll = () => {
const windowHeight = window.innerHeight;
const documentHeight = document.documentElement.scrollHeight;
const scrollTop = window.scrollY;
const percentage = (scrollTop / (documentHeight - windowHeight)) * 100;
setScrollPercentage(Math.round(percentage));
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
return <div>스크롤 진행도: {scrollPercentage}%</div>;
}
WebSocket 연결 관리
RTSP 통신등 실시간 데이터 통신이 필요할 때 사용한다.
function ChatRoom({ roomId }) {
const [messages, setMessages] = useState([]);
useEffect(() => {
const ws = new WebSocket(`ws://chat.server.com/${roomId}`);
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
setMessages(prev => [...prev, message]);
};
return () => ws.close(); // 연결 정리
}, [roomId]);
return (
// ... 채팅방 UI
);
}
기본적인 데이터 fetching
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchUser = async () => {
try {
const response = await axios.get(`/api/users/${userId}`);
setUser(response.data);
} catch (error) {
setError(error.message);
} finally {
setLoading(false);
}
};
fetchUser();
}, [userId]);
if (loading) return <div>로딩중...</div>;
if (error) return <div>에러 발생: {error}</div>;
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
);
}
POST 처리
function SignUpForm() {
const [formData, setFormData] = useState({
username: '',
email: '',
password: ''
});
const [submitStatus, setSubmitStatus] = useState('idle');
const handleSubmit = async (e) => {
e.preventDefault();
setSubmitStatus('loading');
try {
const response = await axios.post('/api/signup', formData);
setSubmitStatus('success');
// 성공 처리 로직
} catch (error) {
setSubmitStatus('error');
// 에러 처리 로직
}
};
return (
<form onSubmit={handleSubmit}>
{/* 폼 필드들... */}
</form>
);
}
Interceptors 활용
API 요청마다 공통적으로 처리해야 하는 로직이 있을 때 유용하다.
const api = axios.create({
baseURL: 'https://api.example.com'
});
function TodoList() {
const [todos, setTodos] = useState([]);
useEffect(() => {
// 요청 인터셉터
api.interceptors.request.use(
config => {
// 요청 전에 헤더에 토큰 추가
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
error => {
return Promise.reject(error);
}
);
// 응답 인터셉터
api.interceptors.response.use(
response => response,
error => {
if (error.response.status === 401) {
// 인증 에러 처리
localStorage.removeItem('token');
window.location.href = '/login';
}
return Promise.reject(error);
}
);
const fetchTodos = async () => {
const response = await api.get('/todos');
setTodos(response.data);
};
fetchTodos();
}, []);
return (
// 렌더링 로직
);
}
검색기능 구현(디바운스 적용)
function SearchComponent() {
const [searchTerm, setSearchTerm] = useState('');
const [results, setResults] = useState([]);
const [isSearching, setIsSearching] = useState(false);
useEffect(() => {
const searchProducts = async () => {
if (!searchTerm) {
setResults([]);
return;
}
setIsSearching(true);
try {
const response = await axios.get(`/api/search`, {
params: { q: searchTerm }
});
setResults(response.data);
} catch (error) {
console.error('검색 중 에러 발생:', error);
} finally {
setIsSearching(false);
}
};
const delay = setTimeout(searchProducts, 500);
return () => clearTimeout(delay);
}, [searchTerm]);
return (
<div>
<input
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="검색어를 입력하세요"
/>
{isSearching && <div>검색중...</div>}
<ul>
{results.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
);
}
병렬요청 처리
function Dashboard() {
const [dashboardData, setDashboardData] = useState({
users: [],
posts: [],
comments: []
});
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchDashboardData = async () => {
try {
const [usersResponse, postsResponse, commentsResponse] =
await axios.all([
axios.get('/api/users'),
axios.get('/api/posts'),
axios.get('/api/comments')
]);
setDashboardData({
users: usersResponse.data,
posts: postsResponse.data,
comments: commentsResponse.data
});
} catch (error) {
console.error('데이터 로딩 실패:', error);
} finally {
setLoading(false);
}
};
fetchDashboardData();
}, []);
if (loading) return <div>대시보드 로딩중...</div>;
return (
// 대시보드 렌더링 로직
);
}
댓글