JS Library/React

커스텀 Hooks

원2 2022. 5. 25. 18:09
728x90
반응형

컴포넌트를 만들다보면 반복되는 로직이 자주 발생하는데 그럴 때 커스텀 Hooks 를 만들어서 반복되는 로직을 쉽게 재사용 하는 방법을 알아보자

 

src에 hooks 라는 디렉토리를 만들고, 그 안에 useInputs 라는 파일을 만들자

*커스텀 Hooks 를 만들 때에는 보통 use 키워드로 시작하는 파일을 만들고 그 안에 함수를 작성

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

 

useInputs.js

import React, {useCallback, useState} from "react";

function useInputs(initialForm) {
    const [form, setForm] = useState(initialForm);

//    change
    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;

 

 

이제 만든 Hook 을 App.js 에서 사용해보자

useReducer 쪽에서 사용하는 inputs 를 없애고 이에 관련된 작업을 useInputs 로 대체해줘야함

새로운 항목을 추가 할 때 input 값을 초기화해야해서 데이터 등록 후 reset() 을 호출해주자

 

App.js

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

function countActiveUsers(users) {
    console.log("active 값이 ture 인 유저의 수를 센는중...");
    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
        },
        {
            id: 3,
            username: 'liz',
            email: 'liz@example.com',
            active: false
        }
    ]
};

// 불변성을 지켜주기 위해서 spread 연산자를 사용
function reducer(state, action) {
    switch (action.type) {
        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:
            return state;

    }
}


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

    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} key={users.id}/>
            <div>활성 사용자 수 : {count}</div>
        </>
    );
}
export default App;

 

다 만들었으면 inputs Hook 을 useReducer 로 만들어보자 지금 만든건 useState 로 만들었음

 

useReducer 버전 (주석은 useState 버전)

 

import React, {useCallback, useReducer} from "react";

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

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;

https://react.vlpt.us/basic/21-custom-hook.html

728x90
반응형

'JS Library > React' 카테고리의 다른 글

API 연동하기, axios  (0) 2022.06.09
Immer 라이브러리  (0) 2022.05.26
Context API 전역 값 관리  (0) 2022.05.26
React.memo  (0) 2022.05.25
useCallback 를 사용하여 함수 재사용  (0) 2022.05.25
React Developer Tools  (0) 2022.05.24