TIL[26일차]훅을 커스텀해보자

남예지·2022년 12월 5일
0

TIL

목록 보기
20/47

커스텀 훅부터 나만의 useQuery를 만드려면 어떻게 해야할까?

이번주는 커스텀 훅을 가지고 훅스 패턴을 사용하고, 제너릭 타입을 배운다.
또 텍스트를 웹 에디터를 만들어보고, 이때 발생하는 보안문제같은 것들을 보게 된다.
실제로 결제기능도 구현해보고, 카카오 지도도 연동해보자.

오늘은 구조분해할당을 리뷰하고, rest-parameter로 객체에서 데이터를 삭제해보고, 커스텀 훅으로 폴더구조를 바꿔볼것이다.

구조분해할당 (=비구조화 할당)

객체의 구조분해 할당


객체가 담긴 변수 안에 키값들을 하나하나 변수로 만들기 보다는 한꺼번에 변수로 만들 수 있다. 이를 구조분해할당이라고 한다.
useQuery또한 함수를 실행시켰더니 리턴값이 객체였다. 그 리턴값이 데이터와 로딩이다.

**이때 객체 순서는 별로 중요하지 않고, 이름이 중요하다.


배열의 구조분해할당

배열의 구조분해할당은 대괄호를 사용한다.

괄호는 useState에서도 볼 수 있다. 이 역시 구조분해할당이 되었다는 것

대신 배열은 순서가 매우 중요하다. 객체와 달리 키 이름은 상관없다. 키가 없기 때문에 마음대로 지어도 괜찮다.
다만 순서대로 들어오기 때문에 순서를 신경쓰자!

배열과 객체의 차이점
객체는 이름이 중요하고 순서가 중요하지 않았다.
배열은 순서가 중요하고 이름이 중요하지 않다.

<객체와 배열 구조분해할당 예시>

마찬가지로 useQuery와 useState도 만들어보자

useQuery 만들기


useQuery라는 함수를 만들어 data와 refetch에 각각 실행할 실행문을 넣고 바로 아래줄처럼

const {data, refetch} = useQuery("FETCH_BOARD")

라고 부르면 data에서는 writer를 꺼낼 수 있고, refetch()하면 실행문이 실행된다.
직접 useQuery처럼 작동하는 함수를 만든것이다. (물론 아예 같지는 않다)

## useState 만들기

Rest 파라미터

특정 객체에서 지우고 싶은 데이터를 delete를 사용해 지우면 원본을 건드리는 일이기 때문에 그리 좋지 않습니다. rest파라미터를 사용하면 원본을 건들이지 않고 삭제할 수 있습니다.

const { money, hobby, ...rest } = child

이러면 money와 hobby가 빠진채로 rest에 저장이 된다.
꼭 rest라고 써야하는 건 아니고 관례로 그렇게 사용한다.

<예시>

const {hobby, dream, ...newMe} = me

//결과
// newMe = {name : "혜원", position : "mento"}

커스텀 훅 (Custom Hook)

useAuth

함수는 함순데 안에 use로 시작하는 함수를 사용하고 있다면 커스텀 훅이고 함수안에 use가 없다면 그냥 함수다.
일반적이지 않은 기능이 들어가 있기때문에 커스텀 훅이라고 부를 뿐 둘 다 함수이다.
eslint가 커스텀 훅을 use로 안감싸면 에러를 보여주지만 에러는 아님.

로그인이 필수인 곳에 들어가면 라우터로 로그인 페이지로 보내는 코드를 필요한 곳에서 import해서 사용할 수 있다.

import { useRouter } from "next/router";
import { useEffect } from "react";

export const useAuth = () => {
  const router = useRouter();

  // 로그인 체크
  useEffect(() => {
    if (localStorage.getItem("accessToken") === null) {
      alert("로그인 후 이용 가능합니다!!!");
      void router.push("/23-03-login-check");
    }
  }, []);
};

프리보드에서 활용할 수 있는 방안은
router만 쓰는 것들 .
쿼리 타입 쓰기 싫다면 .
사용할 수 있다.

클래스 함수 쓸 때는 이런 커스텀한 훅을 쓸 수 없었다. 그렇지만 지금은 함수형 컴포넌트가 나오면서 커스텀 훅으로 바뀌어 분리할 수 있게 되었다.

타입스크립트 Generic 타입

우선 제너릭 타입 전에 타입에 대해 알아보자.

<타입의 종류>

import { useQuery } from "@apollo/client";
import { useState } from "react";

// 1. 문자/숫자/불린(primitive) 타입
const getPrimitive = (arg1: string, arg2: number, arg3: boolean): [boolean, number, string] => {
  return [arg3, arg2, arg1];
};

const result = getPrimitive("철수", 123, true);



// 2. any 타입 => 그냥 자바스크립트랑 같음
const getAny = (arg1: any, arg2: any, arg3: any): [any, any, any] => {
  console.log(arg1 + 1000);
  return [arg3, arg2, arg1];
};

const result = getAny("철수", 123, true);



// 3. unknown 타입
const getUnknown = (arg1: unknown, arg2: unknown, arg3: unknown): [unknown, unknown, unknown] => {
  if (typeof arg1 === "number") console.log(arg1 + 1000);
  return [arg3, arg2, arg1];
};

const result = getUnknown("철수", 123, true);



// 4. generic 타입 - 1
function getGeneric<MyType1, MyType2, MyType3>(arg1: MyType1, arg2: MyType2, arg3: MyType3): [MyType3, MyType2, MyType1] {
  return [arg3, arg2, arg1];
}

const result = getGeneric("철수", 123, true);



// 5. generic 타입 - 2
function getGeneric2<T1, T2, T3>(arg1: T1, arg2: T2, arg3: T3): [T3, T2, T1] {
  return [arg3, arg2, arg1];
}

const result = getGeneric2("철수", 123, true);



// 6. generic 타입 - 3
function getGeneric3<T, U, V>(arg1: T, arg2: U, arg3: V): [V, U, T] {
  return [arg3, arg2, arg1];
}

const result = getGeneric3("철수", 123, true);



// 7. generic 타입 - 4
const getGeneric4 = <T, U, V>(arg1: T, arg2: U, arg3: V): [V, U, T] => {
  return [arg3, arg2, arg1];
};

const result = getGeneric4<string, number, boolean>("철수", 123, true);

제너릭은 타입을 추론해서 그자리에 넣어주는데 인자에 들어오는 타입을 그대로 사용할 수 있다. 실무에서는 보통 T, U, V 등 짧게 줄여 사용한다.

Generic 타입 응용

사용자 입장보다는 제공자 입장에서 많이 쓰게 된다. (useState or useQuery 같은 경우)

제너릭을 응용하는 방법은 아래와 같다.

import { useState } from "react";

// 제공자
export function useMyState<S>(qqq: S): [S, (value) => void] {
  const myState = qqq;

  const mySetState = (value) => {
    console.log(`${myState}에서 ${value}로 state를 변경하겠습니다!!!`);
    console.log(`변경된 ${value}를 사용해서 컴포넌트를 리렌더링 하겠습니다!!!`);
  };

  return [myState, mySetState];
}

// 사용자
const [count, setCount] = useMyState<number>(10);

generic HOF

// 1. HOF - 일반함수
function first<T>(arg1: T) {
  return function second<U>(arg2: U): [T, U] {
    return [arg1, arg2];
  };
}

const result = first("영희")(8);

// 2. HOF - 화살표함수
// prettier-ignore
const first2 = <T>(arg1: T) => <U>(arg2: U): [T, U] => {
    return [arg1, arg2];
};

const result = first2("영희")(8);

// 2. HOF - 화살표함수
// prettier-ignore
const withAuth = <C>(Component: C) => <P>(props: P): [C, P] => {
    return [Component, props];
};

const result = first2("영희")(8);

hof에도 쓸 수 있다면 hoc에도 똑같이 쓰인다.

generic HOC

import { useRouter } from "next/router";
import { ComponentType, useEffect } from "react";

// prettier-ignore
export const withAuth = (ABC: ComponentType) => <P extends {}>(props: P) => {
  const router = useRouter();

  // 로그인 체크
  useEffect(() => {
    if (localStorage.getItem("accessToken") === null) {
      alert("로그인 후 이용 가능합니다!!!");
      void router.push("/23-03-login-check");
    }
  }, []);

  return <ABC {...props} />;
};

저번주 이번주에 걸쳐 실무로 넘어왔다고 볼 수 있다.
그런데 내용이 이해가 안가...'
좀 더 복습에 치중하자.
중고마켓은 코드를 줄이고 컴포넌트를 따로 빼서 재활용을 많이 할 수 있는 방향으로 코드를 짜보자

profile
총총

0개의 댓글