React에서 Hook은 함수형 컴포넌트에서 상태 관리와 라이프사이클 메서드를 사용할 수 있게 해주는 강력한 도구입니다.
useState
// ❌ 잘못된 예시
function MyComponent() {
if (someCondition) {
useEffect(() => {
// ...
}, []);
}
for (let i = 0; i < 3; i++) {
useState(i); // 반복문 내에서 훅 호출 금지
}
function nestedFunction() {
useState(0); // 중첩된 함수 내에서 훅 호출 금지
}
return <div>안녕하세요!</div>;
}
// ✅ 올바른 예시
function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log('컴포넌트가 마운트되었습니다.');
return () => {
console.log('컴포넌트가 언마운트되었습니다.');
};
}, []);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
// ❌ 잘못된 예시: 일반 함수에서 훅 호출
function notAReactComponent() {
const [state, setState] = useState(0); // 오류 발생
}
// ✅ 올바른 예시: 리액트 함수 컴포넌트에서 훅 호출
function MyComponent() {
const [state, setState] = useState(0);
return <div>안녕하세요!</div>;
}
// 🎯 커스텀 훅 예시
function useCustomHook() {
const [state, setState] = useState(0);
useEffect(() => {
console.log('커스텀 훅이 실행되었습니다.');
}, []);
return state;
}
function MyComponent() {
const state = useCustomHook();
return <div>{state}</div>;
}
리액트 라이프사이클은 컴포넌트가 생성, 업데이트, 제거되는 과정을 뜻합니다. 함수형 컴포넌트에서는 useEffect
훅으로 관리할 수 있습니다.
useEffect
훅useEffect
는 기본적으로 컴포넌트가 렌더링된 직후에 실행됩니다.
useEffect(() => {
// 이 부분은 컴포넌트가 마운트될 때 실행됩니다.
return () => {
// 이 부분은 컴포넌트가 언마운트될 때 실행됩니다.
};
}, [dependencies]); // dependencies 배열의 값이 변경될 때 실행
컴포넌트가 처음 렌더링될 때 실행됩니다.
import React, { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
console.log('컴포넌트가 마운트되었습니다.');
return () => {
console.log('컴포넌트가 언마운트될 예정입니다.');
};
}, []); // 빈 배열: 한 번만 실행
return <div>안녕하세요!</div>;
}
컴포넌트의 상태나 속성이 변경될 때 실행됩니다.
import React, { useState, useEffect } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(`Count가 ${count}로 업데이트되었습니다.`);
}, [count]); // count가 변경될 때마다 실행
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
컴포넌트가 DOM에서 제거될 때 실행됩니다.
import React, { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
console.log('컴포넌트가 마운트되었습니다.');
return () => {
console.log('컴포넌트가 언마운트될 예정입니다.');
};
}, []); // 빈 배열: 한 번만 실행
return <div>안녕하세요!</div>;
}
React의 useEffect
Hook은 컴포넌트가 마운트(DOM에 추가)되거나 업데이트, 언마운트(DOM에서 제거)될 때 발생하는 부수 효과(Side Effect)를 처리할 수 있도록 도와줍니다.
useEffect
레퍼런스useEffect(setup, dependencies?)
setup
: 부수 효과를 처리하는 로직을 포함한 함수.dependencies
: 의존성 배열. 이 배열의 값이 변경될 때 setup
함수가 재실행됩니다. 빈 배열([]
)을 전달하면 마운트 시에만 실행됩니다.import { useEffect } from 'react';
import { createConnection } from './chat.js';
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);
}
1️⃣ setup
함수
setup
함수는 실행될 부수 효과 로직을 포함하며, 선택적으로 정리(clean-up) 함수를 반환할 수 있습니다.2️⃣ dependencies
배열
setup
함수가 재실행됩니다.import React, { useEffect } from 'react';
function ExampleComponent() {
useEffect(() => {
console.log('컴포넌트가 마운트되었습니다.');
return () => {
console.log('컴포넌트가 언마운트되었습니다.');
};
}, []); // 빈 배열: 마운트 시 한 번만 실행
return <div>안녕하세요, 리액트!</div>;
}
JSON 데이터를 가져와 화면에 렌더링하기.
import { useEffect, useState } from "react";
export default function AppEffect() {
const [list, setList] = useState([]);
useEffect(() => {
fetch('data/courses_all.json')
.then((res) => res.json())
.then((data) => {
console.log('✅ 데이터 조회 성공');
setList(data);
});
}, []);
return (
<>
<h2 id="title">데이터 가져오기</h2>
<ul>
{list.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>
</>
);
}
useEffect
는 데이터를 가져온 후 상태를 업데이트(setList
)합니다.[]
)로 설정됩니다.필터링 조건에 따라 데이터를 다르게 조회하기.
import { useEffect, useState } from "react";
export default function AppEffect() {
const [list, setList] = useState([]);
const [filter, setFilter] = useState('all');
useEffect(() => {
fetch(`data/courses_${filter}.json`)
.then((res) => res.json())
.then((data) => {
console.log('✅ 데이터 조회 성공');
setList(data);
});
}, [filter]);
return (
<>
<h2 id="title">데이터 가져오기</h2>
<label htmlFor="all">전체</label>
<input
id="all"
type="radio"
value="all"
checked={filter === 'all'}
onChange={(e) => setFilter(e.target.value)}
/>
<label htmlFor="favorite">좋아요</label>
<input
id="favorite"
type="radio"
value="favorite"
checked={filter === 'favorite'}
onChange={(e) => setFilter(e.target.value)}
/>
<ul>
{list.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>
</>
);
}
filter
를 추가하여, 필터 값이 변경될 때마다 새로운 데이터를 가져옵니다.컴포넌트가 언마운트될 때 정리 작업 수행하기.
import { useEffect, useState } from "react";
function Courses() {
const [list, setList] = useState([]);
const [filter, setFilter] = useState('all');
useEffect(() => {
fetch(`data/courses_${filter}.json`)
.then((res) => res.json())
.then((data) => {
console.log('✅ 데이터 조회 성공');
setList(data);
});
return () => {
console.log('❎ 연결 해제~!');
};
}, [filter]);
return (
<>
<label htmlFor="all">전체</label>
<input
id="all"
type="radio"
value="all"
checked={filter === 'all'}
onChange={(e) => setFilter(e.target.value)}
/>
<label htmlFor="favorite">좋아요</label>
<input
id="favorite"
type="radio"
value="favorite"
checked={filter === 'favorite'}
onChange={(e) => setFilter(e.target.value)}
/>
<ul>
{list.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>
</>
);
}
export default function AppEffect() {
const [show, setShow] = useState(true);
return (
<>
<h2 id="title">데이터 가져오기</h2>
<button onClick={() => setShow(!show)}>toggle</button>
<hr />
{show && <Courses />}
</>
);
}
return
문에서 정리 작업을 설정하면 컴포넌트가 DOM에서 제거될 때 해당 작업이 실행됩니다.