해당 글은 useState와 useReducer의 용례를 정리하기 위한 목적으로 서술한다.
공식 문서의 기술에서는 다음과 같은 두 경우에서 useReducer의 사용을 추천한다.
- 다수의 sub-value를 가지는 복잡한 state를 다룰 때
- 다음 state가 이전 상태에 의존적일때
또한 useReducer는 콜백 함수대신 dispatch를 전달 할 수 있으므로 deep update를 트리거하는 컴포넌트의 성능을 최적화할 수 있습니다.
둘 다 useState로도 대체가 가능하기 때문에 구체적인 용례로 파악해보자.
import { useState } from 'react'
import './App.css'
function App() {
/* 이렇게가 아니라 */
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [age, setAge] = useState(0);
/* 이렇게 선언해도 문제 없다. */
const [user, setUser] = useState({
name: '',
email: '',
age: ''
})
/* 다수의 핸들러를 통한 선택적 업데이트의 예시 */
const handleName = (e) => {
setUser({...user, name: e.target.value })
}
const handleEmail = (e) => {
setUser({...user, email: e.target.value })
}
const handleAge = (e) => {
setUser({...user, age: e.target.value })
}
/*
* 단일한 핸들러 함수로 처리한다면
* 문자열을 키값으로 가지는 객체의 특성을 이용해
* 이런 식으로 활용할 수도 있다.
*/
const handleInput = (e) => {
setUser({...user, [e.target.name]: e.target.value})
}
return (
<div className="App">
<div>
<input onChange={handle...} type="text" name="name"/>
<input onChange={handle...} type="text" name="email"/>
<input onChange={handle...} type="text" name="age"/>
<button>제출</button>
</div>
<div>{user.name}</div>
<div>{user.email}</div>
<div>{user.age}</div>
</div>
)
}
export default App
import { useState, useReducer } from 'react'
import './App.css'
const initialState = {
name: '',
email: '',
age: ''
};
const reducer = (state, action) => {
switch (action.type) {
case 'name':
return {
...state,
name: action.payload
};
case 'email':
return {
...state,
email: action.payload
};
case 'age':
return {
...state,
age: action.payload
};
default:
return initialState;
}
}
function App() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div className="App">
<div>
<input onChange={(e) => dispatch({ type: 'name', payload: e.target.value })} type="text" />
<input onChange={(e) => dispatch({ type: 'email', payload: e.target.value })} type="text" />
<input onChange={(e) => dispatch({ type: 'name', payload: e.target.valueAsNumber })} type="text" />
<button>제출</button>
</div>
<div>{user.name}</div>
<div>{user.email}</div>
<div>{user.age}</div>
</div>
)
}
export default App
/* setState에 콜백 함수를 넘기면 해당 콜백의 매개변수는 자동적으로 이전 스테이트가 된다. */
setState((prev) => ...)
/* reducer 는 내부에 매개변수로 이전 state값을 받는다. */
const reducer = (state, action) => {
switch (action.type) {
case 'name':
return {
...state,
name: action.payload
};
case 'email':
return {
...state,
email: action.payload
};
case 'age':
return {
...state,
age: action.payload
};
default:
return initialState;
}
}