상태 업데이트에 주로 썼던 useState
뿐만 아니라 useReducer
로도 업데이트 가능
useState()
에서는 설정하고 싶은 다음 상태를 직접 지정해주는 방식으로 업데이트
useReducer()
에서는 action
을 기반으로 상태 업데이트, 업데이트 시 action
참조
업데이트 시 참조하고 싶은 값이 있다면 dispatch({})
안에 넣어주면 됨
useReducer
는 상태 업데이트를 Component
에서 분리시킬 수 있음
다른 파일에서 작성 후 불러오는 것도 가능
reducer
: 상태를 업데이트하는 함수
function reducer(state, action){
switch(action.type){
case '~~':
return //do Something
}
}
형태는 위와 같음
reducer
는 현재 상태와 action
객체를 매개변수로 받아와서 새로운 상태를 반환해 줌
이 reducer
함수를 useReducer
의 첫번째 매개변수로 넣어줘야 함
const [number, dispatch] = useReducer(reducer, 0);
0은 number
의 초기값이자 기본값임
숫자 뿐 아니라 문자열, 객체도 가능
number
: 현재 상태
dispatch
: action
을 발생시키는 함수 JSP에서의 forwardDispatcher
처럼 보내는 의미
import React, { useState } from "react";
function Counter() {
const [number, setNumber] = useState(0);
const onIncrease = () => {
setNumber(prevNumber => prevNumber + 1);
};
const onDecrease = () => {
setNumber(prevNumber => prevNumber - 1);
};
return (
<div>
<h1>{number}</h1>
<button onClick={onIncrease}>+1</button>
<button onClick={onDecrease}>-1</button>
</div>
);
}
export default Counter;
useState
로 구현한 단순한 카운터 프로그램
import React, { useReducer } from "react";
function reducer(state, action) {
switch (action.type) {
case "INCREMENT":
return state + 1;
case "DECREMENT":
return state - 1;
default:
throw new Error("Unhandled action");
}
}
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;
useReducer
로 구현한 단순한 카운터 프로그램
정리하면 useReducer()
의 두번째 매개변수인 0이 number
에 처음 적용이 되고, +1
버튼이 클릭되면, dispatch
에 의해 action
이 발생하고 reducer
함수가 동작 state
는 초기값이자 number
값과 동일한 0이고, +1
을 해서 1을 return
-1
도 마찬가지로 dispatch
에 의해 현재 number
의 값이 state
로 전달되고 계산된 값 state-1
을 return
두번째 예제, onToggle
과 onRemove
기능이 있는 페이지 기능 구현
<UserList
users={users}
onToggle={onToggle}
onRemove={onRemove}
></UserList>
Component
에 다음처럼 넘겨주는 App.js가 있다고 가정
각 user
들에는 id가 있다. 따라서, onToggle
이나 onRemove
클릭시, id를 전달받을 수 있음
<button onClick={() => onRemove(id)}>삭제</button>
위의 경우 App.js 에서 처리 방법은 다음과 같음
function reducer(state, action) {
switch (action.type) {
case "TOGGLE_USER":
return {
...state,
users: state.users.map(user =>
user.id === action.id ? { ...user, active: !user.active } : user
)
};
case "REMOVE_USER":
return {
...state,
users: state.users.filter(user => user.id !== action.id)
};
default:
throw new Error("Unhandled action");
}
}
dispatch 부분은 밑과 같음
const onToggle = useCallback(id => {
dispatch({
type: "TOGGLE_USER",
id
});
}, []);
const onRemove = useCallback(id => {
dispatch({
type: "REMOVE_USER",
id
});
}, []);
UserList Component
로부터 받은 id
값을 dispatch
를 통해 reducer
함수에 전달
//onToggle
users: state.users.map(user =>
user.id === action.id ? { ...user, active: !user.active } : user
)
위의 경우에서 users
는 return
되어 onToggle
함수 안에 쓰이는 배열형 객체
state.users
는 dispatch
를 호출한 시점에서 넘겨지는 state
//useReducer 사용부분
const [state, dispatch] = useReducer(reducer, initialState);
쉽게 풀어서 말하면 dispatch
로 호출한 시점의 state
를 사용해 새로운 상태를 만들고 (위를 예로 들면 state.users
가 새로운 상태로 변경됨) 그것을 return
하면, 새로운 state
가 호출한 시점의 state
를 덮어씌우게 됨
즉, function App()
의 state
와 function reducer(state, action)
의 state
는 같으면서 같지 않음. dispatch
로 호출시 App state
가 reducer state
가 되지만, 후에 reducer state
가 return
한 값이 App state
가 됨