-
React - 커스텀 hook 만들기React 2020. 9. 13. 19:18
1. useInputs.js 생성하고 input에 관한 함수 만들기
import { useState, useCallback } from 'react'; // initialForm 은 input form에서 관리할 초기값 function useInputs(initialForm) { // form이라는 새로운 상태 선언 - 그 상태의 초기값은 파라미터로 가져온 initialForm const [form, setForm] = useState(initialForm); const onChange = useCallback(e => { const {name, value} = e.target; // form을 업데이트 setForm(form => ({ ...form, [name]: value})); // 의존하는 다른 상태 없음 빈 - 배열 사용 }, []); // 초기값을로 설정해주겠다는 뜻 const reset = useCallback(() => setForm(initialForm), [initialForm]); // 이제 useInputs사용하면 초기값을 파라미터로 받아오고, // onChange로 상태 관리 // reset으로 초기화 return [form, onChange, reset]; } export default useInputs;
2. App.js 에 적용
1) initState 객체에서 inputs 부분 삭제
2) useInputs 컴포넌트 선언
import useInputs from './useInputs';
3) { username, email } 선언 부분, onChange()부분 삭제
4) useInput()선언하고, username과 email form에서 추출
const [form, onChange, reset] = useInputs({ username: '', email: '', }); const { username, email } = form;
5) reset은 onCreate할 때, 추출
const onCreate = useCallback(() => { dispatch({ type: 'CREATE_USER', user: { id: nextId.current, username, email, } }); nextId.current += 1; reset(); }, [username, email, reset]);
결과 코드
import React, { useRef, useReducer, useMemo, useCallback } from 'react'; import UserList from './UserList'; import CreateUser from './CreateUser'; import useInputs from './useInputs'; function countActiveUsers(users){ console.log('활성 사용자 수를 세는 중...'); return users.filter(user => user.active).length; } const initialState = { 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, } ] } 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) }; 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 action'); } } function App() { const [state, dispatch] = useReducer(reducer, initialState); const [form, onChange, reset] = useInputs({ username: '', email: '', }); const { username, email } = form; const nextId = useRef(4); const { users } = state; const onCreate = useCallback(() => { dispatch({ type: 'CREATE_USER', user: { id: nextId.current, username, email, } }); nextId.current += 1; reset(); }, [username, email, reset]); 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;
useState 대신 useReducer 사용하는 방법
import { useReducer, useCallback } from 'react'; function reducer(state, action){ switch (action.type) { case 'CHANGE': return { ...state, [action.name]: action.value } case 'RESET': return Object.keys(state).reduce((acc, current) => { acc[current] = ''; return acc; }, {}); default: return state; } } function useInputs(initialForm) { const [form, dispatch] = useReducer(reducer, initialForm); const onChange = useCallback(e => { const {name, value} = e.target; dispatch({ type: 'CHANGE', name, value }); }, []); const reset = useCallback(() => { dispatch({ type: 'REMOVE', }) }, []); return [form, onChange, reset]; } export default useInputs;
이전 코드
import React, { useRef, useReducer, useMemo, useCallback } from 'react'; import UserList from './UserList'; import CreateUser from './CreateUser'; function countActiveUsers(users){ console.log('활성 사용자 수를 세는 중...'); return users.filter(user => user.active).length; } 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, } ] } 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) }; 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 action'); } } function App() { const [state, dispatch] = useReducer(reducer, initialState); 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' 카테고리의 다른 글
React - Userdispatch Context (0) 2020.09.13 React - Context API(전역 값 관리) (0) 2020.09.13 React - App 컴포넌트에서 useReducer사용 (0) 2020.09.11 React - useReducer (0) 2020.09.11 React - 컴포넌트 리렌더링 방지(React.memo) (0) 2020.09.11