본문 바로가기
개발 공부 시리즈/Slack클론코딩

[인프런 강의] zerocho Slack 클론 코딩 (9) - 커스텀 훅 만들기

by 그레이웅 2022. 10. 26. 13:33
반응형

 

이전 포스팅은 회원가입 페이지 만들기에 대해 포스팅하였다.

2022.10.24 - [개발 공부 시리즈/Slack클론코딩] - [인프런 강의] zerocho Slack 클론 코딩 (8) - 회원가입 페이지 만들기

 

이번 포스팅에서는 커스텀 훅을 만들어보겠다.

 

※ 이 포스팅은 zerocho님의 slack 클론 코딩 강좌를 따라 하면서 정리해놓은 포스팅입니다.

 

 

1. 중복 코드 제거하기

alecture/pages/SignUp/index.tsx

 

const SignUp = () => {
  const [email, setEmail] = useState('');
  const [nickname, setNickName] = useState('');
  
  const [password, setPassword] = useState('');
  const [passwordCheck, setPasswordCheck] = useState('');

  //비밀번호 , 비밀번호확인 같은지 여부 판단
  const [mismatchError, setMissmatchError] = useState(false);


  const onChangeEmail = useCallback((e) => {
    setEmail(e.target.value);
  },[]);

  const onChangeNickname = useCallback((e) => {
    setNickName(e.target.value);
  },[]);

  //비밀번호 변경 함수
  const onChangePassword = useCallback((e) => {
    setPassword(e.target.value);
    setMissmatchError(e.target.value !== passwordCheck)
  },[passwordCheck]);

  //비밀번호 확인 변경 함수
  const onChangePasswordCheck = useCallback((e) => {
    setPasswordCheck(e.target.value);
    setMissmatchError(e.target.value !== password)
  },[password]);
  
  
 //......

 

이전 포스팅에서 만들었던 회원가입 페이지이다.

이 페이지의 코드 중 email과 nickName, onChangeEmail, onChangeNickname 같은 코드를 두 번 사용하는 형태가 되는데 커스텀 훅을 사용해 중복을 제거할 수 있다.

 

 

 

2. CUSTOM HOOK 만들기

 

hooks 폴더에 useInput.ts 파일을 생성한다.

 

useInput.ts

//useInput.ts

import { Dispatch, SetStateAction, useCallback, useState} from "react"

type ReturnTypes<T = any> = [T, (e: any) => void, Dispatch<SetStateAction<T>>]

const useInput = <T = any> (initialData: T) : ReturnTypes<T> => {
  const [value, setValue] = useState(initialData);
  const handler = useCallback((e) => {
    setValue(e.target.value);
  }, [])
  return [ value, handler, setValue];
} 

export default useInput;

 

useInput.ts는 Input에 대한 커스텀 훅을 만든 예제이다.

 

SignUp/index.tsx 에 다음과 같은 코드들을 추가한다. 

 

index.tsx 

 

import React, {useCallback, useState} from "react";
import { Header, Form, Label, Input, Button, LinkContainer, Error } from './styles';
import { Link } from 'react-router-dom';

//커스텀 훅 추가
import useInput from '@hooks/useInput';

const SignUp = () => {
  //단순한 input 중복일때 useInput 사용
  const [email, onChangeEmail] = useInput('');
  const [nickname,onChangeNickname] = useInput('');


  //useInput을 사용했을때 커스터 마이징이 필요할 때 가운데를 빈 값으로 두면된다.
  const [password, ,setPassword] = useInput('');
  const [passwordCheck, ,setPasswordCheck] = useInput('');

  //비밀번호 , 비밀번호확인 같은지 여부 판단
  const [mismatchError, setMissmatchError] = useState(false);


  //비밀번호 변경 함수
  const onChangePassword = useCallback((e) => {
    setPassword(e.target.value);
    setMissmatchError(e.target.value !== passwordCheck)
  },[passwordCheck]);

  //비밀번호 확인 변경 함수
  const onChangePasswordCheck = useCallback((e) => {
    setPasswordCheck(e.target.value);
    setMissmatchError(e.target.value !== password)
  },[password]);

 

email과 nickname의 setEmail, setNickname을 useInput 의 setValue를 사용하여 중복을 제거하였다.

onChangeEmail, onChangeNickname 함수도 useInput의 handler 부분으로 보내지게 되어 마찬가지로 중복을 제거시켰다.

 

onChangePassword와 onChangePasswordCheck 함수는 중복되는 코드도 있지만 중복되지 않는 코드들도 있다.

그렇기 때문에 가운데에 빈 값으로 두면 커스터마이징이 필요한 코드를 커스텀 훅과 같이 사용할 수 있다.

 

 

3. CUSTOM HOOK 코드 살펴보기
import { Dispatch, SetStateAction, useCallback, useState} from "react"

//매개변수는 타입을 꼭 붙여줘야한다. 
//리턴 등은 타입을 타입스크립트가 추론해 주어서 명시하지 않아도 되지만
//매개변수는 타입을 명시해줘야함
//어떤 타입이 들어올지 모를땐 any
// : 이후에는 리턴 타입을 설정해준다. 
// Dispatch 와 SetStateAction은 React가 제공하는 타입이다.


//리턴타입을 변수로 설정 할 수 있다.
//리턴 타입에 any를 안 넣을 려면 any 대신 ChangeEvent<HTMLInputElement>
//e.target.value 대신 e.target.value as unkown as T를 넣으면 해결 된다.
type ReturnTypes<T = any> = [T, (e: any) => void, Dispatch<SetStateAction<T>>]

const useInput = <T = any> (initialData: T) : ReturnTypes<T> => {
  console.log(initialData);
  const [value, setValue] = useState(initialData);
  const handler = useCallback((e) => {
    setValue(e.target.value);
  }, [])
  return [ value, handler, setValue];
} 

export default useInput;

 

타입 스크립트를 사용해 useInput이라는 커스텀 훅을 만들었다.

input의 onChange 함수의 작동이 일어나게 되면, 값을 바꾸어주는 커스텀 훅이다.

 

타입 스크립트는 리턴 타입은 타입이 자동적으로 판단할 수 있지만 매개변수는 타입을 꼭 명시해 주어야 한다.

useInput의 타입은 <T>라는 제네릭 타입으로 받게된다.

제네릭으로 선언하고 <T : any > 라는 말은 어떤 타입이 들어올지 모른다는 말이다.

(intialData : T )는 받는 매개변수고 이전에 제네릭으로 any라고 설정해 준 값이 들어오게 되며 

: 뒤쪽은 리턴할 타입을 명시한다.

 

위처럼 type으로 선언하여 사용할 수도 있다.

 

dispatch 함수는 react에서 제공하는 함수이고 , dispatch()를 사용하면 HTML 안에서 reducer함수를 동작시킬 수 있다.

SetStateAction 타입은 S(initial state)라는 제너릭을 가지고 있고, S 타입의 Parameter(prevState)를 입력받아 S타입의 값을 리턴하는 함수이다.

 

두 가지를 제네릭 타입으로 같이 사용하게 된다.

 

위 코드를 다음과 같이 ChangeEvent <HTMLInputElement>와 e.target.value as unknown as T로 변경하여 사용할 수 있다.

import { Dispatch, SetStateAction, useCallback, useState, ChangeEvent } from 'react';
							//변경
type ReturnTypes<T> = [T, (e: ChangeEvent<HTMLInputElement>) => void, Dispatch<SetStateAction<T>>];

const useInput = <T>(initialData: T): ReturnTypes<T> => {
     const [value, setValue] = useState(initialData);
     const handler = useCallback((e: ChangeEvent<HTMLInputElement>) => {
     //변경
     setValue((e.target.value as unknown) as T);
	}, []);
    return [value, handler, setValue];
};

export default useInput;

 

ChangeEvent <HTMLInputElement>는 Input태그의 이벤트가 일어날 때 이벤트의 타입을 찾을 수 있다.

만약 textarea 태그이면 <HTMLTextAreaElement>로 바꾸어주면 된다.

 

 

 

다음과 같이 입력을 하고 submit을 눌러도 customHook의 onChange 이벤트가 값을 제대로 전달하는 것을 볼 수 있다.

 

반응형

댓글