-
React - App 컴포넌트에서 useReducer사용React 2020. 9. 11. 15:20
React - useReducer
이전에는 useState로 상태 업데이트 해줬음 useReducer로도 할 수 있음 useState는 setValue(5); 와 설정하고 싶은 다음 상태를 직접 지정해줘서 업데이트함 useReducer는 action이라는 객체를 기반으로 상태를 �
startersdev.tistory.com
1. App 컴포넌트에서 사용할 초기 상태를 컴포넌트 밖에 선언해 줌
const initialState = { inputs: { username: '', email: '', }, users: [ { id: 1, username: 'starters', email: 'public.starters@gmail.com', active: true, }, { id: 2, username: 'tester', email: 'tester@gmail.com', active: false, }, { id: 3, username: 'jajajojo', email: 'jajajojo@gmail.com', active: false, } ] }
2. App컴포넌트에서 사용한 모든 로직 지우기, 내부 props도 지우기
function App() { return ( <> <CreateUser /> <UserList users={[]}/> <div>활성 사용자 수: 0</div> </> ); }
- users에 임시로 빈 배열 넣고, count는 0으로
3. useState 대신에 useReducer 불러오기
import React, { useRef, useReducer, useMemo, useCallback } from 'react';
4. reducer 틀 잡기
function reducer(state, action){ return state; } function App() { const [state, dispatch] = useReducer(reducer, initialState); return ( <> <CreateUser /> <UserList users={[]}/> <div>활성 사용자 수: 0</div> </> ); }
5. state 안에 있는 users와 inputs 비구조 할당으로 추출 후, 컴포넌트를 통해 props로 전달
function App() { const [state, dispatch] = useReducer(reducer, initialState); const { users } = state; const { username, email } = state.inputs; return ( <> <CreateUser username={username} email={email} /> <UserList users={users}/> <div>활성 사용자 수: 0</div> </> ); }
6. onChange함수 구현하고 사용
const onChange = useCallback(e => { const { name, value } = e.target; dispatch({ type: 'CHANGE_INPUT', name, value }); }, []); return ( <> <CreateUser username={username} email={email} onChange={onChange} /> ...
7. onCreate()
const onCreate = useCallback(() => { dispatch({ type: 'CREATE_USER', user: { id: 1, username, email, } }); }, [username, email]); return ( <> <CreateUser
- id 는 임의로 1, 나중에 useRef로 관리해주어야 함
1) nextId 값 관리
function App() { const [state, dispatch] = useReducer(reducer, initialState); const nextId = useRef(4); const { users } = state;
- App함수 상단에 선언, 초기값은 4 기존에 3개 들어있기 때문
2) create 함수에 넣어줌
const onCreate = useCallback(() => { dispatch({ type: 'CREATE_USER', user: { id: nextId.current, username, email, } }); nextId.current += 1; }, [username, email]);
3) reducer 함수에도 추가
function reducer(state, action){ switch (action.type) { case 'CHANGE_INPUT': return { ...state, inputs: { ...state.inputs, [action.name]: action.value } }; case 'CREATE_USER': return { inputs: initialState.inputs, users: state.users.concat(action.user) } default: throw new Error('Unhandled action'); } }
4) props도 지정
<CreateUser username={username} email={email} onChange={onChange} onCreate={onCreate} />
-> 이러고 나면 새 글 생성할 수 있음
8. onToggle / onRemove
- reducer 안에 먼저 추가
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) };
- 함수 생성, props 추가
const onToggle = useCallback(id => { dispatch({ type: 'TOGGLE_USER', id }); }, []); const onRemove = useCallback(id => { dispatch({ type: 'REMOVE_USER', id }); }, []); return ( <> <CreateUser username={username} email={email} onChange={onChange} onCreate={onCreate} /> <UserList users={users} onToggle={onToggle} onRemove={onRemove}/> <div>활성 사용자 수: 0</div> </> );
9. 활성 사용자 수
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> </>
- 이전과 동일, useMemo 사용하고 props 추가
※ 언제 useReducer 사용하고 useState 사용할 지
- 확실하게 정해진 것은 없음
- 값이 한두개이거나 boolean값이면 useState가 편할 것
- 컴포넌트에서 관리하는 값이 여러개이거나 구조가 복잡하면 useReducer가 나을 수 있음
- setUsers, setInputs 처럼 useState자주 사용되면 useReducer 사용을 고려해보는 것도 좋음
이전 코드
import React, { useRef, useState, useMemo, useCallback } from 'react'; import UserList from './UserList'; import CreateUser from './CreateUser'; 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: 'starters', email: 'public.starters@gmail.com', active: true, }, { id: 2, username: 'tester', email: 'tester@gmail.com', active: false, }, { id: 3, username: 'jajajojo', email: 'jajajojo@gmail.com', active: false, } ]); const nextId = useRef(4); const onCreate = useCallback(() => { const user = { id: nextId.current, username, email, }; setUsers(users => users.concat(user)); setInputs({ username: '', email: '' }); console.log(nextId.current); nextId.current += 1; }, [username, email]); const onRemove = useCallback(id => { setUsers(users => users.filter(user => user.id !== id)) }, []); const onToggle = useCallback(id => { setUsers(users => 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;
'React' 카테고리의 다른 글
React - Context API(전역 값 관리) (0) 2020.09.13 React - 커스텀 hook 만들기 (0) 2020.09.13 React - useReducer (0) 2020.09.11 React - 컴포넌트 리렌더링 방지(React.memo) (0) 2020.09.11 React - 함수 재사용(useCallback) (0) 2020.09.11