(state, action) => {
//state와 action을 이용해 연산을 수행한 후 새로운 상태(newState)를 리턴한다.
return newState;
};
상태를 변경할 때는 리듀서 함수의 첫 번째 인자로 기존 상태가 전달된다. 기존 상태는 불변성을 가져야 하므로 그대록 두고, 새로운 상태를 만들어서 리턴하면 이것이 새로운 상태가 된다.
리액트는 상태가 바뀌면 UI도 갱신되므로 상태의 변경 추적이 디버깅 시 필요한데, 리듀서를 사용하면 과거 시점의 상태가 그대로 유지되므로 언제든지 과거 시점의 상태 데이터를 확인할 수 있고 시간대별로 상태가 어떻게 변경됐는지를 추적할 수 있다.
단순히 상태를 관리하고 변경하는 거라면 useState 훅을 사용해도 충분하지만 useReducer 훅을 사용하면 아래와 같은 장점이 있다.
import { useReducer } from 'react'
useReducer 훅에 리듀서 함수와 초기 상태를 인자로 전달하여 호출하면 상태와 상태 변경을 위해 메시지를 전달할 수 있는 dispatch 함수가 리턴된다.
dispatch 함수가 미리 정의한 형식의 메시지를 전달하면 상태를 변경하도록 리듀서 함수를 작성해야 한다.
기본 구문
const [state, dispatch] = useReducer(reducer, initialState);
매개 변수
state
: 상태dispatch
: 상태를 변경하는 메서드reducer
: 새로운 상태를 리턴하는 리듀서 함수initialState
: 초기 상태로 지정할 객체
// infoReducer.js
const initialState = { name: "Taylor", age: 42 };
const infoReducer = (state, action) => {
switch (action.type) {
case "changed_name":
return {
name: action.nextName,
age: state.age,
};
case "incremented_age":
return {
name: state.name,
age: state.age + 1,
};
default:
return state;
}
};
export { initialState, infoReducer };
// Form.js
import { useReducer } from "react";
import { initialState, infoReducer } from "./infoReducer";
function Form() {
const [state, dispatch] = useReducer(infoReducer, initialState);
const handleInputChange = (e) => {
dispatch({
type: "changed_name",
nextName: e.target.value,
});
};
const handleButtonClick = () => {
dispatch({ type: "incremented_age" });
};
return (
<>
<input value={state.name} onChange={handleInputChange} />
<button onClick={handleButtonClick}>Increment age</button>
<p>
Hello, {state.name}. You are {state.age}.
</p>
</>
);
}
export default Form;