useReducer는 useState와 같이 상태관리를 도와주는 Hook이다.
이 Hook 함수를 사용하면 컴포넌트의 상태 업데이트 로직을 컴포넌트에서 분리시킬 수 있다.
상태 업데이트 로직을 컴포넌트 바깥에 작성 할 수도 있고, 다른 파일에 작성 후 불러와서 사용 할 수도 있다.
같은 작업을 useState와 useReducer로 해보았다.
import React, { useRef , useState, useMemo, useCallback } from 'react';
import CreateUser from './CreateUser';
import UserList from './UserList';
// active값이 true인 사용자의 수를 세어 화면에 렌더링하기.
function countActiveUsers(users) {
console.log('활성사용자수세는중')
return users.filter(user=>user.active).length;
}
function App() {
const [inputs, setInputs] = useState({
username: '',
email: ''
});
const {username, email} = inputs;
const onChange = useCallback(e => {
const {name,value} = e.target;
setInputs({
...inputs,
[name] : value
});
}, [inputs]);
const [users, setUsers] = useState([
{
id: 1,
username: 'velopert',
email: 'public.velopert@gmail.com',
active: true
},
{
id: 2,
username: 'test1',
email: 'test1@gmail.com',
active: true
},
{
id: 3,
username: 'test3',
email: 'test3@gmail.com',
active: false
},
]);
const nextId = useRef(4);
//useRef로 관리하는 변수는 값이 바뀐다고해서
//컴포넌트가 리렌더링되지 않는다.
const onCreate = useCallback( () => {
const user = {
id: nextId.current,
username,
email
};
// 배열에 새 항목 추가하기
//1. spread 연산자를 사용하는 방법
//setUsers([...users,user]);
//2. concat 함수를 사용하는 방법
setUsers(users.concat(user));
setInputs({
username: '',
email: ''
});
nextId.current += 1;
}, [username, email]);
// 배열에 항목 삭제하기
//user.id가 파라미터로 일치하지 않는 원소만 추출해서 새로운 배열을 만듦.(filter사용)
//user.id가 id와 같은 것을 제거.
const onRemove = useCallback(
id => {
setUsers(users.filter(user => user.id !==id));
}, []);
// 배열 항목 수정하기(상태수정)
// 배열의 불변성을 유지하면서 배열을 업데이트 하기위해 map 함수 사용
// id 값을 비교하여 id가 다르다면 그대로 두고, 같다면 active 값을 반전 시킴.
const onToggle = useCallback(
id => {
setUsers(
users.map(user =>
user.id === id? {...user, active : !user.active} : user
)
);
}, []);
const count = useMemo(() => countActiveUsers(users), [users]);
return (
<>
<CreateUser
username={username}
email={email}
onChange={onChange}
onCreate={onCreate} />
<UserList users={users} onRemove={onRemove} onToggle={onToggle} />
<div>활성사용자수:{count} </div>
</>
);
}
export default App;
import React, { useRef, useMemo, useCallback, useReducer } from 'react';
import CreateUser from './CreateUser';
import UserList from './UserList';
// active값이 true인 사용자의 수를 세어 화면에 렌더링하기.
function countActiveUsers(users) {
console.log('활성사용자수세는중')
return users.filter(user=>user.active).length;
}
const initilState = {
inputs: {
username: '',
email: ''
},
users: [
{
id: 1,
username: 'velopert',
email: 'public.velopert@gmail.com',
active: true
},
{
id: 2,
username: 'test1',
email: 'test1@gmail.com',
active: true
},
{
id: 3,
username: 'test3',
email: 'test3@gmail.com',
active: false
}
]
}
function reducer(state,action) {
switch (action.type) {
case 'CHANGE_INPUT':
return {
...state,
inputs: {
...state.inputs,
[action.name]: action.value
}
};
case 'CREATE_USER':
return {
inputs: initilState.inputs,
users: state.users.concat(action.user)
};
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:
return state;
}
}
function App() {
const [state, dispatch] = useReducer(reducer,initilState);
const nextId = useRef(4)
const {users} = state;
const {username,email} = state.inputs;
const onChange = useCallback(e => {
const {name,value} = e.target;
dispatch({
type: 'CHANGE_INPUT',
name, value
})
},[]);
const onCreate = useCallback(() => {
dispatch({
type: 'CREATE_USER',
user:{
id: nextId.current,
username,
email
}
});
nextId.current += 1;
},[username,email]);
const onToggle = useCallback(id => {
dispatch({
type: 'TOGGLE_USER',
id
});
},[]);
const onRemove = useCallback(id => {
dispatch({
type: 'REMOVE_USER',
id
});
},[]);
const count = useMemo(() => countActiveUsers(users), [users]);
return(
<>
<CreateUser username={username} email={email} onChange={onChange} onCreate={onCreate}/>
<UserList users={users} onToggle={onToggle} onRemove={onRemove}/>
<div>활성사용자 수 : {count}</div>
</>
);
}
export default App;
React_Router에서 props 전달하기 (0) | 2021.11.22 |
---|---|
React_React Icons (0) | 2021.11.18 |
React_useMemo (0) | 2021.11.11 |
React_useEffect (0) | 2021.11.11 |
React _ 배열 항목 수정하기 (0) | 2021.10.03 |
댓글 영역