[React] 커스텀 Hooks 만들기

Noma·2021년 9월 27일
0

이 글은 velopert님의 커스텀 Hooks 만들기 부분을 공부하고 정리한 글입니다.

언제 사용하는가?

컴포넌트를 만들다보면, 반복되는 로직이 자주 발생한다. 이때 커스텀 Hooks를 만들면 그러한 상황에서 반복되는 로직을 쉽게 재사용할 수 있다.

커스텀 훅 만들기

보통 use 라는 키워드로 시작하는 파일을 만들고 그 안에 함수를 작성한다. ( ex. useInputs.js )

그리고 그냥, 그 안에서 useState, useEffect, useReducer, useCallback 등 Hooks를 사용하여 원하는 기능을 구현해주고, 컴포넌트에서 사용하고 싶은 값들을 반환해주면 된다.

보통 src 폴더 안에 hooks 폴더를 따로 만들어 커스텀 훅만 정리한다.

예제1 (useState 사용)
input을 관리하는 코드는 다룰 때마다 꽤나 비슷한 코드가 반복된다. useInpusts.js라는 파일을 생성해 커스텀 훅을 만들어보자.

// useInputs.js
import {useState, useCallback} from 'react';

function useInputs(initialState){
  const [form, setForm]=useState(initialState);
  
  //change
  const onChange=useCallback(e=>{
    const {name, value}=e.target;
    setForm(form=>({...form,[name]:value}));
  },[])
  const reset=useCallback(()=>setForm(initialState),[initialState]);
  
  return [form, onChange, reset];
}
export default useInputs;

이제 useInputs 훅을 App.js에서 사용해보자. (🌈부분만 확인하면 된다.)

import React, { useRef, useReducer, useMemo, useCallback } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';
import useInputs from './hooks/useInputs'; //🌈

function countActiveUsers(users) {
  return users.filter(user => user.active).length;
}

const initialState = {
  users: [
    {
      id: 1,
      username: 'velopert',
      email: 'public.velopert@gmail.com',
      active: true
    },
    {
      id: 2,
      username: 'tester',
      email: 'tester@example.com',
      active: false
    }
  ]
};

function reducer(state, action) {
  switch (action.type) {
    case 'CREATE_USER':
      return {
        users: state.users.concat(action.user)
      };
    case 'TOGGLE_USER':
      return {
        users: state.users.map(user =>
          user.id === action.id ? { ...user, active: !user.active } : user
        )
      };
    case 'REMOVE_USER':
      return {
        users: state.users.filter(user => user.id !== action.id)
      };
    default:
      return state;
  }
}

function App() {
  const [{ username, email }, onChange, reset] = useInputs({
    username: '',
    email: ''
  }); //🌈
  const [state, dispatch] = useReducer(reducer, initialState);
  const nextId = useRef(4);

  const { users } = state;

  const onCreate = useCallback(() => {
    dispatch({
      type: 'CREATE_USER',
      user: {
        id: nextId.current,
        username,
        email
      }
    });
    reset();
    nextId.current += 1;
  }, [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;

+ useReducer를 사용하여 커스텀 훅 만드는 방법

//useInputs.js

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);
  // change
  const onChange = useCallback(e => {
    const { name, value } = e.target;
    dispatch({ type: 'CHANGE', name, value });
  }, []);
  const reset = useCallback(() => dispatch({ type: 'RESET' }), []);
  return [form, onChange, reset];
}

export default useInputs;
profile
Frontend Web/App Engineer

0개의 댓글