훅이란?
:: 함수 컴포넌트가 리액트 생명주기와 state를 연결하는 수단이다.
훅의 도입 배경은?
:: 컴포트간 재사용이 어렵고, 로직의 캡슐화가 어려웠다.
e.g) 창의 너비를 감지하는 custom hook을 생성해보자
import { useState, useEffect } from 'react';
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
// 언마운트 시 리스너 제거 (정리)
return () => window.removeEventListener('resize', handleResize);
}, []);
return width; // 현재 너비 값만 반환
}
위에 custom hook 을 A컴포넌트에서 사용할 수 있고 B컴포넌트에서 사용할 수 있다.
function Navbar() {
const width = useWindowWidth(); // 로직 재사용
return (
<nav>
{width < 768 ? <MobileMenu /> : <DesktopMenu />}
</nav>
);
}
useState란?
:: 함수 컴포넌트에 state를 추가하고 관리할 수 있는 훅이다.
updater함수를 사용하는것이 항상 좋은가?
:: 동일한 이벤트 핸들러 내에서는 여러 state 업데이트를 하는 경우 예상하는 데이터 결과를 받기 위해서는 updater함수를 사용하는 것이 좋다.
const handleClick = () => {
setCounter((prevData) => prevData + 1);
setCounter((prevData) => prevData + 1);
setCounter((prevData) => prevData + 1);
}
만약에 setCounter(data + 1) 3번 호출하면 기존 값에서 +1된 값만 나올 수 있다. 그렇기 떄문에, 하나의 이벤트 핸들러에 state를 여러번 호출해야한다면 예상된 결과값을 얻기 위해서는 updater함수를 호출하는것이 좋다.
:: useReducer는 useState의 대체제이다. 값이 여러 복잡한경우 state로 관리하지 않고 useReducer를 통해 값을 관리한다.
e.g)
CounterReducer.tsx를 작성해준다.
interface CounterState {
count: number;
}
interface CounterAction {
type: 'INCREMENT' | 'DECREMENT';
}
function counterReducer(state: CounterState, action: CounterAction): CounterState {
switch (action.type) {
case 'INCREMENT':
return {count: state.count + 1};
case 'DECREMENT':
return {count: state.count - 1};
default:
throw new Error('Unhandled action type');
}
}
const initialState: CounterState = {count: 0};
export {
counterReducer,
initialState
}
Counter.tsx에서 사용예시
import {useReducer} from 'react';
import {counterReducer, initialState} from "../reducer/count";
function Calculator() {
const [state, dispatch] = useReducer(counterReducer, initialState);
return (
<>
<div>
<p>Count : {state.count}</p>
<button onClick={() => dispatch({type: 'INCREMENT'})}>+</button>
<button onClick={() => dispatch({type: 'DECREMENT'})}>-</button>
</div>
</>
)
}
export default Calculator;
실행과정을 설명하자면, 사용자가 이벤트를 발생하면 등록된 이벤트 핸들러 내에서 상태를 바꾸고 싶은 dispatch를 호출한다. 이때 호출된 dispatch 안에 action인자를 넣어 호출한다.
그러면 등록된 reducer는 action인자와 이전 상태값을 전달받아 값을 조작한다.
1.useEffect훅 내의 반응형 의존성이 로직에 어떤 영향을 미치는가?
아래와 같은 특성이 있다.
useEffect(() => {
},[]) // mounted시에 실행
useEffect(() => {
},[state]) // mounted와 state값이 변경이 될떄 실행
useEffect(() => {
}) // 리렌더링 시에
useEffect(() => {
// 1. 마운트된 직후 (Mounted)
console.log("마운트됨!");
return () => {
// 2. 언마운트 직전 (Before Unmount)
console.log("사라지기 직전!");
};
}, []);