리액트 훅(React Hooks)은 리액트 16.8 버전부터 추가된 기능
클래스 컴포넌트와 생명주기 메서드를 이용하여 작업을 하던 기존 방식에서 벗어나
함수형 컴포넌트에서도 더 직관적인 함수를 이용하여 작업할 수 있게 만든 기능
훅을 도입함으로써 상태 관련 로직을 추상화할 수 있게 되어
재사용과 테스트가 가능하게 되었습니다. 즉, 훅을 통해 계층의 변화 없이 상태 관련 로직을 재사용할 수 있게 되었다.
리액트 훅 사용 규칙
useState()
const [state, setState] = useState(initialState);
상태를 설정할 때 사용하는 훅 API로 클래스 컴포넌트의 생명주기 메소드 constructor()에서 상태를 초기화하는 것과 비슷한 역할을 하는 API이다.
API는 인자로 초기 상태(initialState)를 받고, 반환 값으로 현재 상태(state)와 상태를 설정하는 함수(setState)를 반환.
- useEffect()
useEffect(callback, dependency);
클래스 컴포넌트의 생명주기 메소드 componentDidMount(), componentDidUpdate, componentWillUnmount()를 통합한 것과 같은 API로 side effect를 발생하는 작업을 수행하는 훅 API. Side effect란 다른 컴포넌트에 영향을 줄 수 있고 렌더링 과정에서는 구현할 수 없는 작업을 말함, 그 예로는 컴포넌트 안에서 데이터 가져오거나 구독하기, DOM을 직접 조작하기 등이 있음
useEffect(() => {
// side effect를 발생하는 작업
const timerId = setTimeout( () => console.log('useEffect') );
// side effect를 발생하는 작업을 정리
return () => clearTimeout(timerId);
});
앞서 언급한 클래스 컴포넌트의 생명주기 메서드 componentDidMount()와 componentDidUpdate()는 컴포넌트가 렌더링 될 때마다 side effect가 발생하는 작업을 수행하고, componentDidUmount()는 컴포넌트가 언마운트될 때 이 작업에 대한 정리 작업을 수행
이러한 세 메소드를 합친 것과 같은 useEffect()는 첫 번째 인자로 전달받은 콜백 함수 내부에서 side effect가 발생하는 작업을 수행하고, 이에 대한 정리 작업을 수행하는 cleanup 함수를 반환
또한, 위와 같이 두번째 인자로 아무것도 넣지 않은 경우에는 매 렌더링 시마다 콜백 함수를 실행하고, 다음 렌더링이 실행되기 전에는 cleanup 함수를 실행
useEffect(() => {
console.log('useEffect');
}, []);
두 번째 인자에 빈 배열을 넣는 경우, 마운트 될 때에 콜백 함수 내부를 실행하고 언마운트 될 때에 cleanup 함수를 실행. 이를 사용할 때에는 마운트 될 때의 state값과 props값이 언마운트될 때까지 유지된다는 점을 주의
useContext()
const themes = { dark: { background: 'black' }, light: { background: 'white' } }
// context 객체
const ThemeContext = React.createContex(themes.dark);
// value prop에 의해 context의 현재 값이 결정됨
const App = () => {
return ( <ThemeContext.Provider value={themes.light}> <Button /> </ThemeContext.Provider> )
}
const Button = () => {
// 현재 값
const contextValue = useContext(context);
return ( <button style={{background: contextValue.background}}> Button </button> )
}
인자로 context 객체를 받아 객체의 현재 값을 반환. context 객체는 useContext가 호출된 컴포넌트에서 가장 가까이에 위치한 <Context.Provider>의 props로 전달된 value에 따라 값이 변경. 또한, 값이 변경될 때마다 이 훅을 호출한 컴포넌트는 리렌더링
useReducer()
const [state, dispatch] = useReducer(reducer, initialState, init);
앞서 살펴본 useState()의 대체 함수로 다양한 컴포넌트 상황에 따라 상태 값을 설정하는 훅 API
// 초기화 함수
const init = (initialValue) => {
return { count: initialValue };
}
// 리듀서 함수
const reducer(state, action) => {
switch(action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 };
case 'DECREMENT':
return { ...state, count: state.count - 1 };
case 'RESET':
return init(action.payload);
}
}
const Counter = ({ initialValue }) => {
const [state, dispatch] = useReducer(reducer, initialCount, init);
return (<>
Count: {state.count}
<button onClick={() => dispatch({type: 'reset', payload: initialCount})}> Reset </button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>);
}
useReducer()는 첫 번째 인자로 현재 상태(state)와 행동(action)을 인자로 받는 reducer 함수를, 두 번째 인자로 상태의 초기값을, 세 번째 인자로는 상태 초기화 함수를 넣고 현재 상태(state)와 액션을 발생시키는 함수(dispatch)를 반환
Counter 컴포넌트 내 버튼을 클릭하면 dispatch 함수에 의해 각 버튼마다 다른 액션 객체가 설정 또, dispatch는 reducer를 호출하여 reducer가 주어진 액션 객체 값에 따라 상태 변경을 하도록 함. 이 때, reducer 함수에서 상태 변경이 이루어질 때는 반드시 불변성을 지켜야 한다.
이러한 useReducer()는 useState()에 비해 유동적으로 상태를 관리할 수 있고, 상태 관련 로직을 컴포넌트 밖으로 꺼낼 수 있다는 장점이 있음
useCallback()
const memoizedCallback = useCallback(callback, dependency);
렌더링 최적화에 사용하는 훅 API로 렌더링 과정에서 두 번째 인자로 주어진 의존 배열(dependency)의 값이 바뀌면 첫 번째 인자로 주어진 콜백함수(callback)를 새로 생성하여 반환
의존 배열에 따른 작동 방식은 useEffect()와 같이 배열을 넣지 않은 경우에는 매 렌더링마다, 빈 배열을 넣는 경우에는 마운트 때에만, 특정 값을 넣는 경우에는 특정 값이 변하여 렌더링될 때에만 해당 훅 API가 실행행
const onClick = useCallback(e => {
e.preventDefault();
setNumber(number + 1);
), [number]};
useCallback()으로 정의한 클릭 이벤트 핸들러 함수(onClick) 예시. 함수는 number의 값이 변할 때마다 number의 값에 1을 더해주는 함수를 기억하고있다가 클릭 이벤트가 발생할 경우 해당 함수를 실행
useMemo()
const memoizedValue = useMemo(callback, dependency);
연산 최적화에 사용하는 API로 렌더링 과정에서 두 번째 인자로 받은 의존 배열(dependency)내 값이 바뀌는 경우에만 첫 번째 인자로 받은 콜백함수를 실행하여 구한 값을 반환하는 함수
useRef()
const ref = useRef(initialValue);
함수형 컴포넌트에서 ref를 쉽게 사용할 수 있도록 하는 훅 API
useRef()는 인자로 받은 값으로 초기화된 변경 가능한 ref 객체를 반환. 이 객체는 컴포넌트의 전 생애주기동안 유지되며, ref.current와 같이 current 속성에 접근하여 현재 가리키는 객체에 접근할 수 있음.
또한, 이는 가변 값을 유지하기 편리하다는 장점이 있음