Custom Hook 만들기

G-NOTE·2021년 6월 11일
0

React

목록 보기
9/27
post-custom-banner
  • src 디렉토리에 useInputs.js 커스텀 훅 컴포넌트 파일을 만든다.
import { useState, useCallback } from "react";

// initialForm : 해당 input에서 관리할 초기값
function useInputs(initialForm) {
  const [form, setForm] = useState(initialForm);

  const onChange = useCallback((e) => {
    const { name, value } = e.target;
    setForm((form) => ({ ...form, [name]: value }));
  }, []);

  const reset = useCallback(() => setForm(initialForm), [initialForm]);

  return [form, onChange, reset];
}

export default useInputs;
  • App.js에서 커스텀 훅 적용하기
import { useRef, useReducer, useMemo, useCallback } from "react";
import UserList from "./UserList";
import CreateUser from "./CreateUser";
import useInputs from "./useInputs";

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

const initialState = {
  users: [
    { id: 1, username: "bae", age: 22, active: true },
    { id: 2, username: "lee", age: 21, active: false },
    { id: 3, username: "lim", age: 25, active: false },
  ],
};

function reducer(state, action) {
  switch (action.type) {
    case "CREATE_USER":
      return {
        // 작성된 내용 input에서 삭제
        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: "",
    age: "",
  });
  const { username, age } = form;
  const nextId = useRef(4);
  const { users } = state;

  const onCreate = useCallback(() => {
    dispatch({
      type: "CREATE_USER",
      user: {
        id: nextId.current,
        username,
        age,
      },
    });
    nextId.current += 1;
    reset();
  }, [username, age, 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}
        age={age}
        onChange={onChange}
        onCreate={onCreate}
      />
      <UserList users={users} onToggle={onToggle} onRemove={onRemove} />
      <div>활성 사용자 수 : {count}</div>
    </>
  );
}
export default App;
  • onCreate 함수의 deps에서 resets는 안넣어도 무방하나 eslint 규칙상 삽입한 것이다.
profile
FE Developer
post-custom-banner

0개의 댓글