보통 상태관리를 할 때 useState를 사용했었는데, useReducer를 통해서도 상태관리를 할 수 있고 상태 업데이트 로직을 컴포넌트에서 분리시킬 수 있다. 이렇게 함으로써 나중에 context API나 Redux 사용 시 업데이트 로직을 전달해줄 수 있을것 같다.
import React, { useReducer } from 'react';
function reducer(state, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
function Counter() {
const [number, dispatch] = useReducer(reducer, 0);
const onIncrease = () => {
dispatch({ type: 'INCREMENT' });
};
const onDecrease = () => {
dispatch({ type: 'DECREMENT' });
};
return (
<div>
<h1>{number}</h1>
<button onClick={onIncrease}>+1</button>
<button onClick={onDecrease}>-1</button>
</div>
);
}
export default Counter;
간단히 Counter 컴포넌트를 구현해봤다. useReducer의 첫번째 인자로 따로 로직을 구현한 reducer를 전달해주고, 두번째 인자로 initial state값을 전달해준다. initial state에사 class형 컴포넌트에서 state = {} 로 정의했던 것 처럼 전달해주면 될 것 같다.
dispatch({ type: 'CHANGE_INPUT', name, value });
만약 위처럼 작성시에 전달한 name, value 값들은 reducer 함수 내에서 action.name, action.value로 받을 수 있다.
function reducer(state, action) {
switch (action.type) {
case 'CHANGE_INPUT':
return {
...state,
inputs: {
...state.inputs,
[action.name]: action.value
}
};
default:
return state;
}
}
그런데 무조건 useReducer를 통해 값을 관리하는것이 좋은것만은 아니다. 단일값, 단순한 숫자 등이라면 useState로 관리하는게 낫겠지만 컴포넌트 구조가 복잡해지고 관리해야 할 값도 여러개라면 useReducer로 관리하는것이 더 편할 것 이다.
useContext 훅으로 context API 를 사용해 전역적으로 사용할 수 있는 값을 관리할 수 있다.
const MyContext = createContext("defaultValue");
위 처럼 context를 생성 후
const text = useContext(MyContext);
방식으로 만들어둔 context를 가져올 수 있다.
context를 사용하고자 할 컴포넌트에 MyContext.Provider를 안씌우면 createContext시 전달한 디폴트 값이 넘어가지만, <MyContext.Provider value={"Hello"} /> 처럼 작성하면 컴포넌트에 value를 전달하여 컴포넌트 내에서 사용할 수 있다. 부모, 자식 컴포넌트간에 관계가 필요 없이 바로 전달해 줄 수 있는것이다.