ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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
Designed by Tistory.