Custom Hooks

Jaeseok Han·2023년 11월 3일
0

React Basic

목록 보기
22/30

Custom Hook

커스텀 훅 성질

1. 일반적인 훅과 동일한 규칙

커스텀 훅은 리액트에서 제공하는 일반적인 훅(useState, userEffect, useContext )과 동일한 규칙과 규약을 따른다.

2. 컴포넌트 단순화(코드 최소화)

커스텀 훅을 사용하면 복잡한 로직을 커스텀 훅으로 추상화하고 이 로직을 컴포넌트 코드 밖에서 분리함으로써, 컴포넌트 코드가 더 간결해지고 가독성이 향상된다.

3. 기능 재사용

커스텀 훅을 사용하여 공통 기능을 여러 컴포넌트 간에 공유할 수 있다. 이는 코드 중복을 방지하고 코드 재사용성을 높이는데 도움이 된다.
예를 들어, 데이터 가져오기, 양식 처리, 인증, 로깅과 같은 일반적인 작업을 하는 커스텀 훅을 만들어 다른 컴포넌트에서 쉽게 재사용할 수 있다.

toggle

import { useState } from 'react';

const ToggleExample = () => {
  const [show, setShow] = useState(false);
  return (
    <div>
      <h4>toggle custom hook</h4>
      <button className='btn' onClick={() => setShow(!show)}>
        toggle
      </button>
      {show && <h4>some stuff</h4>}
    </div>
  );
};
export default ToggleExample;

토글로 렌더링 여부를 상태 값으로 처리하는 기능이 컴포넌트에 속해있다
이러한 기능을 다른 컴포넌트에서 공통적으로 사용할 경우 toggle에 대한 커스텀 훅을 만들어 사용하면 하나의 코드로 여러곳에서 사용할 수 있으며, 컴포넌트 외부에 기능을 만들어 컴포넌트의 코드가 간결해진다.

useToggle.js

import { useState } from "react";

const useToggle = (defaultValue) => {
    const [show, setShow] = useState(defaultValue);
    const toggle = () => {
        setShow(!show)
    }

    return {show, toggle};
}

export default useToggle;

import useToggle from './useToggle';

const ToggleExample = () => {
  const {show, toggle} = useToggle(true);

  return (
    <div>
      <h4>toggle custom hook</h4>
      <button className='btn' onClick={toggle}>
        toggle
      </button>
      {show && <h4>some stuff</h4>}
    </div>
  );
};
export default ToggleExample;

Challenge

  • fetch-data.js 확인
  • 커스텀 fetch 훅을 설정해본다.
  • 힌트
    • 훅은 isLoading, isError, user를 반환
    • URL을 매개변수로 받아야 한다.

fetch-data.js

import { useEffect, useState } from 'react';
const url = 'https://api.github.com/users/Jaeseokkong';

const FetchData = () => {
  const [isLoading, setIsLoading] = useState(true);
  const [isError, setIsError] = useState(false);
  const [user, setUser] = useState(null);

  useEffect(() => {
    const fetchUser = async () => {
      try {
        const resp = await fetch(url);
        // console.log(resp);
        if (!resp.ok) {
          setIsError(true);
          setIsLoading(false);
          return;
        }

        const user = await resp.json();
        setUser(user);
      } catch (error) {
        setIsError(true);
        // console.log(error);
      }
      // hide loading
      setIsLoading(false);
    };
    fetchUser();
  }, []);
  // order matters
  // don't place user JSX before loading or error

  if (isLoading) {
    return <h2>Loading...</h2>;
  }
  if (isError) {
    return <h2>There was an error...</h2>;
  }
  const { avatar_url, name, company, bio } = user;
  return (
    <div>
      <img
        style={{ width: '100px', borderRadius: '25px' }}
        src={avatar_url}
        alt={name}
      />
      <h2>{name}</h2>
      <h4>works at {company}</h4>
      <p>{bio}</p>
    </div>
  );
};
export default FetchData;

풀이

useFetchPerson.js

import { useEffect, useState } from "react";

const useFetch = (url) => {
    const [isLoading, setIsLoading] = useState(true);
    const [isError, setIsError] = useState(false);
    const [user, setUser] = useState(null);  

    useEffect(() => {
        const fetchUser = async () => {
            try {
                const resp = await fetch(url);
                // console.log(resp);
                if (!resp.ok) {
                  setIsError(true);
                  setIsLoading(false);
                  return;
                }
        
                const user = await resp.json();
                setUser(user);
              } catch (error) {
                setIsError(true);
                // console.log(error);
              }
              // hide loading
              setIsLoading(false);
            };
            fetchUser();
    },[]);

    return {isLoading, isError, user}
}

export default useFetch;

import { useEffect, useState } from 'react';
import useFetch from '../starter/useFetch';
const url = 'https://api.github.com/users/Jaeseokkong';

const FetchData = () => {
  const {isLoading, isError, user} = useFetch(url);
  // order matters
  // don't place user JSX before loading or error

  if (isLoading) {
    return <h2>Loading...</h2>;
  }
  if (isError) {
    return <h2>There was an error...</h2>;
  }
  const { avatar_url, name, company, bio } = user;
  return (
    <div>
      <img
        style={{ width: '1![](https://velog.velcdn.com/images/wotjr294/post/b7f7b9a1-6f86-4c20-a4d1-49a53e0ab610/image.gif)
00px', borderRadius: '25px' }}
        src={avatar_url}
        alt={name}
      />
      <h2>{name}</h2>
      <h4>works at {company}</h4>
      <p>{bio}</p>
    </div>
  );
};
export default FetchData;

공통적으로 만들어서도 사용가능

useFecth.js

import { useEffect, useState } from "react";

const useFetch = (url) => {
    const [isLoading, setIsLoading] = useState(true);
    const [isError, setIsError] = useState(false);
    const [data, setData] = useState(null);  

    useEffect(() => {
        const fetchData = async () => {
            try {
                const resp = await fetch(url);
                // console.log(resp);
                if (!resp.ok) {
                  setIsError(true);
                  setIsLoading(false);
                  return;
                }
        
                const response = await resp.json();
                setData(response);
              } catch (error) {
                setIsError(true);
                // console.log(error);
              }
              // hide loading
              setIsLoading(false);
            };
            fetchData();
    },[]);

    return {isLoading, isError, data}
}

export default useFetch;

import { useEffect, useState } from 'react';
import useFetch from './useFetch';
const url = 'https://api.github.com/users/Jaeseokkong';

const FetchData = () => {
  const {isLoading, isError, data: user} = useFetch(url);
  // order matters
  // don't place user JSX before loading or error

  if (isLoading) {
    return <h2>Loading...</h2>;
  }
  if (isError) {
    return <h2>There was an error...</h2>;
  }
  const { avatar_url, name, company, bio } = user;
  return (
    <div>
      <img
        style={{ width: '100px', borderRadius: '25px' }}
        src={avatar_url}
        alt={name}
      />
      <h2>{name}</h2>
      <h4>works at {company}</h4>
      <p>{bio}</p>
    </div>
  );
};
export default FetchData;

response 값을 데이터로 넣고 커스텀훅을 사용하는 컴포넌트에서 data의 값을 지정하여 사용한다.

0개의 댓글