이제 useReducer가 어떻게 돌아가는지 알았으니 App.js
에다가 적용을 시켜보자.
첫번째로 해야할 일은 App 컴퍼넌트에서 사용할 초기 상태를 컴퍼넌트 바깥에 선언하는 것이다.
inputs의 초기값과 users의 초기값을 선언해주면된다.
const initialState ={
inputs: {
username: '',
email: '',
},
users:[
{
id: 1,
username: 'carrot',
email: 'carrot@gamil.com',
active: true,
},
{
id: 2,
username: 'apple',
email: 'apple@gamil.com',
active: true,
},
{
id: 3,
username: 'tomato',
email: 'tomato@gamil.com',
active: false,
}
]
}
그다음 App 컴퍼넌트 내부에서 선언한 내용을 전부 제거한다.
function App() {
const style = {
margin : '20px'
}
return (
<div style={style}>
<CreateUser/>
<UserList users = {[]} />
<div>활성 사용자 수: 0</div>
</div>
);
}
reducer를 작성한다.
function reducer(state,action){
return state;
}
App.js내부에 useReducer를 작성하고 객체의 비구조화 할당으로 데이터를 쉽게 사용할 수 있게 변경해준다.
const [state, dispatch] = useReducer(reducer, initialState)
const {users} = state;
const {username, email} = state.inputs;
const onChange = useCallback(e=> {
const {name, value} = e.tarfet;
dispatch({
type:'CHANGE_INPUT',
name,
value
})
},[])
reducer를 switch문으로 나누어서 action.type마다 다른 작업을 수행하게 작성한다. onChange의 경우는 불변성 유지를 위해서 배열을 새로 만들고 기존에 있던 값을 집어 넣은뒤에 값을 수정하면 된다.
function reducer(state,action){
switch(action.type){
case 'CHANGE_INPUT':
return{
...state,
inputs:{
...state.inputs,
[action.name] : action.value
}
};
default:
throw new Error('Unhandled adction');
}
}
const onCreate = useCallback (() => {
dispatch({
type:'CREATE_USER',
user: {
id: nextId.current,
username,
email,
}
});
nextId.current += 1;
},[username, email])
id값은 nexId.current값을 username,email 값은 사용자가 입력한 값을 받아온다.
case 'CREATE_USER':
return{
inputs: initialState.inputs,
users: state.users.concat(action.user)
}
action.type 가 'CREATE_USER'인 경우에
inputs 를 초기의 inputs값으로 변경하고, users 배열은 초기 배열의 값에다가 action으로 가져온 user 항목을 추가한 값으로 변경된다.
usestate로 사용한 경우에는 input 초기화와 배열항목 추가를 따로 했었지만, reducer의 경우에는 이 두가지를 동시에 선언이 가능하다.
const onToggle = useCallback (id => {
dispatch({
type: 'TOGGLE_USER',
id
});
}, []);
const onRemove = useCallback( id => {
dispatch({
type:'REMOVE_USER',
id
});
}, []);
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 adction');
}
function countActiveUsers(users) {
console.log('활성 사용자 수를 세는중 ...');
return users.filter(user => user.active).length;
}
const count =useMemo(() => countActiveUsers(users),[users])
이전에 만든 함수를 사용해서 작성한다.