Custom Hook

장현욱(Artlogy)·2022년 8월 24일
0

React

목록 보기
16/24
post-thumbnail

컴포넌트를 만들다보면, 반복되는 로직이 자주 발생한다.
예를 들면 input을 관리하거나 서버와 통신하는 로직을 생각 할 수 있다.

이번에는 이러한 상황에 커스텀 훅을 만들어 반복되는 로직을 쉽게 재사용 하는법을 알아보자.

hooks/useInputs.js

import { useState, useCallback } from "react";

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

    return [form, onChange, reset];
}
export default useInputs;

커스텀 훅은 위처럼 원하는 기능을 구현해주고, 컴포넌트에서 사용하고 싶은 값들을 반환해주면된다.
그냥 리액트 훅을 사용한 함수일 뿐이라고 생각하면 편하다.

Custom hooks는 use라는 키워드를 사용해 파일을 만드는 것이 관습이다.

이제 만든 useInputs hook을 사용해보자.

Array.jsx

import React, { useCallback, useMemo, useState } from "react";
import useInputs from "../hooks/useInputs";

const User = React.memo(function User({ user, onRemove, onToggle }) {
    return (
        <div>
            {user.active ? (
                <b
                    onClick={() => {
                        onToggle(user.id);
                    }}
                    style={{ color: "green" }}
                >
                    {user.username}
                </b>
            ) : (
                <b
                    onClick={() => {
                        onToggle(user.id);
                    }}
                >
                    {user.username}
                </b>
            )}
            <span>({user.email})</span>
            <button onClick={() => onRemove(user.id)}>삭제</button>
        </div>
    );
});

const UserList = React.memo(({ users, onRemove, onToggle }) => {
    return (
        <div>
            {users.map((el, idx) => (
                <>
                    <User
                        key={idx}
                        user={el}
                        onRemove={onRemove}
                        onToggle={onToggle}
                    ></User>
                </>
            ))}
        </div>
    );
});

const CreateUser = React.memo(({ username, email, onChange, onCreate }) => {
    return (
        <div>
            <input
                name="username"
                placeholder="계정명"
                onChange={onChange}
                value={username}
            />
            <input
                name="email"
                placeholder="이메일"
                onChange={onChange}
                value={email}
            />
            <button onClick={onCreate}>등록</button>
        </div>
    );
});

const Array = () => {
    const [users, setUsers] = useState([
        {
            id: 1,
            username: "차가운 그녀",
            email: "cold_fish@gmail.com",
            active: true,
        },
        {
            id: 2,
            username: "기네스 맥주",
            email: "guness@gmail.com",
            active: false,
        },
        {
            id: 3,
            username: "나를잡아줘",
            email: "holdme@gmail.com",
            active: false,
        },
    ]);
    const [form, onChange, reset] = useInputs({ username: "", email: "" });

    const onCreate = useCallback(() => {
        // spread를 이용한 방법
        setUsers((users) => [
            ...users,
            {
                id: users.length + 1,
                email: form?.email,
                username: form?.username,
                active: false,
            },
        ]);
        //concat을 이용한 방법
        // setUsers((users) =>
        //     users.concat({
        //         id: users.length + 1,
        //         email: email,
        //         username: username,
        //         active: false,
        //     })
        // );
        reset();
    }, [form, reset]);
    const onRemove = useCallback((id) => {
        // 해당 id(key)를 제외한 배열로 반환
        setUsers((users) => users.filter((el) => el.id !== id));
    }, []);
    const onToggle = useCallback((id) => {
        setUsers((users) =>
            users.map((el) =>
                el.id === id ? { ...el, active: !el.active } : el
            )
        );
    }, []);
    function countActiveUsers(users) {
        console.log("활성 사용자 수를 세는중...");
        return users.filter((user) => user.active).length;
    }
    const count = useMemo(() => {
        return countActiveUsers(users);
    }, [users]);
    return (
        <>
            <CreateUser
                username={form?.username}
                email={form?.email}
                onChange={onChange}
                onCreate={onCreate}
            />
            <UserList users={users} onRemove={onRemove} onToggle={onToggle} />
            <div>활성사용자 수 :{count}</div>
        </>
    );
};

export default React.memo(Array);

0개의 댓글