리액트 Hooks(2) - useReducer
- 🚩 useReducer
함수형 컴포넌트에서 현재 상태, 그리고 업데이트를 위한 정보를 담은 action 값을 전달받고 새로운 상태를 반환하는 함수
☝ 1 | useReducer 함수의 기본적인 사용 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import React, {useReducer} from 'react';
function reducer(state, action){
//action의 타입에 따른 작업 수행
switch(action.type){
case 'INCREMENT':
return { value: state.value + 1 };
case 'DECREMENT':
return { value: state.value - 1 };
default:
return state;
}
}
const Counter = () => {
const [state, dispatch] = useReducer(reducer, {value : 0})
return (
<div>
<p>
현재 카운터 값 <b>{state.value}</b>
</p>
<button onClick={()=>dispatch({type:'INCREMENT'})}>+1</button>
<button onClick={()=>dispatch({type:'DECREMENT'})}>-1</button>
</div>
);
};
export default Counter;
- useReducer 함수는 첫 번째 인자에 리듀서 함수를 넣습니다. 두 번째 인자에는 리듀서의 기본 값을 넣습니다.
const [state, dispatch] = useReducer(reducer, {value : 0})
이 부분에서 state는 현재 가리키는 것의 상태(여기서는 value)를, dispatch는 액션을 발생시키는 함수를 정의한 것입니다.- button onClick 부분을 보면 dispatch 함수 내에 액션 값을 넣어 주면서, reducer 함수가 호출됩니다.
- 이처럼 컴포넌트 업데이트 로직(reducer 함수가 맡은 부분)을 컴포넌트 바깥으로 빼낼 수 있게 됩니다.
☝ 2 | useReducer 함수로 인풋 상태 관리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import React, { useReducer } from 'react';
function reducer(state, action){
return {
...state, // state 값을 여기에 복사하고,
[action.name]: action.value // 값을 덮어씌운다.
};
}
const Info = () => {
const [state, dispatch] = useReducer(reducer, {
name: '',
nickname: ''
});
const {name, nickname} = state;
const onChange = e =>{
dispatch(e.target);
}
return (
<div>
<div>
<input name = "name" value={name} onChange={onChange}/>
<input name = "nickname" value={nickname} onChange={onChange}/>
</div>
<div>
<div>
이름 : {name}
</div>
<div>
닉네임 : {nickname}
</div>
</div>
</div>
);
};
export default Info;
- useReducer에서 state를 name, nickname으로 정의하였습니다.
const {name, nickname} = state
이 부분을 통해, 위에서 정의한 state 값이 각각 name, nickname에 들어갔습니다. - 🎁 객체 비구조화 할당 문법- 쉽게 말해 useReucer의 첫 번째 인자에 들어간 리듀서 함수는, useState에서 state를 변경하는 함수와 하는 역할이 비슷하다고 생각하면 됩니다.
- 단, useState 에서 state를 변경하는 함수는 그 state 값을 그대로 사용하지만, useReducer 에서 state를 변경하는 reducer 함수는 추가적으로 가공하여 새로운 상태를 반환하는 것에서 그 내용의 차이가 있습니다.
- 이제 reducer 함수를 정의한 부분을 보겠습니다.
- [action.name] : action.value
- onChange 함수에서 reducer 함수를 호출한 부분을 확인해 보면 action 값을 e.target 으로 지정했으므로, action.name 은 e.target.name 과 같고, action.value는 e.target.value와 같습니다.
- e.target.name 여기에선 해당 input의 name의 값을 말합니다.
- e.target.value는 input의 value 값을 말합니다.
- 이로써 state의 값을 value 로 변경할 수 있게 됩니다.
- [action.name] : action.value
useReducer 함수의 액션은 어떤 값도 사용이 가능합니다. 즉, 인자로 액션 값을 넣는 dispatch 함수에 e.target 를 액션 값으로 넣었습니다. 이벤트 객체가 지니고 있는 e.target 값 자체를 넣은 것입니다.
input 이 여러개였을 경우 기존에는 useState를 여러번 사용했고, 각각 다른 state setter 함수도 여러 개가 만들어지게 됩니다. 따라서 그에 따른 onChange 핸들링 함수도 여러 개 존재했었습니다.
[예] name, nickname state를 정의하고 setName, setNickname 이라는 함수도 정의함
1 2 3 4 5 6 7 8 9
const [name, setName] = useState(''); const [nickname, setNickname] = useState(''); const onChangeName = e => { setName(e.target.value); }; const onChangeNickname = e => { setNickname(e.target.value); }
그러나 useReducer를 사용함으로써 인풋의 갯수가 계속 많아지더라도 useState를 여러 번 사용할 필요가 없이 코드를 간결하게 유지할 수 있습니다.
이 포스팅은 리액트를 다루는 기술(저자 김민준)
을 학습하는 과정에서 개인적으로 정리한 내용입니다.