React
Meta가 만든 UI 라이브러리. 컴포넌트 단위로 UI를 구성하고, 상태 변화에 따라 자동으로 리렌더링한다.
컴포넌트
// 함수형 컴포넌트 (현재 표준)
function Hello({ name }: { name: string }) {
return <h1>안녕, {name}</h1>
}Hooks
useState
const [count, setCount] = useState(0)
setCount(count + 1) // 직접 값 지정
setCount((prev) => prev + 1) // 이전 상태 기반 (권장)useEffect
// 마운트 시 1회
useEffect(() => {
fetchData()
}, [])
// 의존성 변경 시
useEffect(() => {
fetchUser(userId)
}, [userId])
// 클린업 (언마운트 or 재실행 전)
useEffect(() => {
const timer = setInterval(() => {}, 1000)
return () => clearInterval(timer)
}, [])useRef
// DOM 접근
const inputRef = useRef<HTMLInputElement>(null)
inputRef.current?.focus()
// 리렌더링 없이 값 유지
const countRef = useRef(0)
countRef.current += 1useMemo / useCallback
// 값 메모이제이션 (연산 비용이 클 때)
const sorted = useMemo(() => items.sort(), [items])
// 함수 메모이제이션 (자식 컴포넌트에 props로 넘길 때)
const handleClick = useCallback(() => {
doSomething(id)
}, [id])useContext
const ThemeContext = createContext<'light' | 'dark'>('light')
// Provider
<ThemeContext.Provider value="dark">
<App />
</ThemeContext.Provider>
// 사용
const theme = useContext(ThemeContext)useReducer
type Action = { type: 'increment' } | { type: 'reset' }
function reducer(state: number, action: Action) {
switch (action.type) {
case 'increment': return state + 1
case 'reset': return 0
}
}
const [count, dispatch] = useReducer(reducer, 0)
dispatch({ type: 'increment' })커스텀 Hook
반복되는 로직을 추출해 재사용.
function useFetch<T>(url: string) {
const [data, setData] = useState<T | null>(null)
const [loading, setLoading] = useState(true)
useEffect(() => {
fetch(url)
.then((res) => res.json())
.then((data) => { setData(data); setLoading(false) })
}, [url])
return { data, loading }
}
// 사용
const { data, loading } = useFetch<User[]>('/api/users')렌더링 최적화
// React.memo — props가 바뀌지 않으면 리렌더링 스킵
const Child = React.memo(({ value }: { value: number }) => {
return <div>{value}</div>
})| 도구 | 용도 |
|---|---|
React.memo |
컴포넌트 리렌더링 방지 |
useMemo |
값 재계산 방지 |
useCallback |
함수 재생성 방지 |
이벤트 처리
// 타입 명시
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
setValue(e.target.value)
}
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault()
}조건부 렌더링 & 리스트
// 조건부
{isLoggedIn && <Dashboard />}
{isLoggedIn ? <Dashboard /> : <Login />}
// 리스트 (key 필수)
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}