본문 바로가기
REACT

커스텀 훅으로 HTTP 요청 리팩토링

by 일태찡 2023. 2. 17.

 

이 글은 HTTP 요청 내용에서 이어집니다.

https://iltae.tistory.com/2

 

HTTP 요청 보내기

HTTP 요청의 기본 개념 클라이언트에 직접적으로 서버를 연결하면 자바스크립트 코드는 누구나 확인할 수 있기 때문에 인증 정보를 노출시키는 행위이며 보안에 취약해집니다. HTTP 요청에 대한 A

iltae.tistory.com

 

투 두 리스트를 예시로 HTTP 요청을 위한 커스텀 훅 구성을 먼저 해봅시다.

 

use-http.js

import { useState, useCallback } from "react";

const useHttp = () => {
    const [isLoading, setIsLoading] = useState(false);
    const [error, setError] = useState(null);

    // requestConfig를 매개변수로 하고 이는 URL을 포함해 여러 설정 사항들을 포함하는 객체여야함
    // 그 객체에 이용할 값들을 연결해 줌
    const sendRequest = useCallback(async (requestConfig, applyData) => {
        setIsLoading(true);
        setError(null);
        try {
            const response = await fetch(
                requestConfig.url, {
                method: requestConfig.method ? requestConfig.method : 'GET',
                headers: requestConfig.headers ? requestConfig : {},
                body: requestConfig.body ? JSON.stringify(requestConfig.body) : null
            }
            );

            if (!response.ok) {
                throw new Error('Request failed!');
            }

            const data = await response.json();

            // 함수를 매개변수로 받아 데이터를 넘겨줌
            applyData(data);
        } catch (err) {
            setError(err.message || 'Something went wrong!');
        }
        setIsLoading(false);
    }, []);

    // 로딩 상태, 에러상태 그리고 함수를 반환함
    return {
        // isLoading: isLoading,
        // error: error,
        // sendRequest: sendRequest
        // 모던 자바스크립트에서 속성명과 변수명이 같은 경우 이렇게 편하게 줄일 수 있음
        isLoading,
        error,
        sendRequest
    }
};

export default useHttp;

 

  • 의존성을 최소화하기 위해 useHttp에 인자를 설정하지 않고 sendRequest에 설정해 줍니다.
  • 요청의 여러 경우를 유동적으로 대처하기 위해 값이 빌 경우에 대한 설정을 해줍니다.
  • 여러 상태와 요청 함수를 반환해 줍니다.
  • 이 함수를 호출할 때 의존성 배열에 함수를 넣어야 해 무한 루프를 방지하기 위해 useCallback으로 함수를 저장합니다.

 

그다음에 이를 불러올 컴퍼넌트를 구성해 보겠습니다.

 

App.js

import React, { useEffect, useState, useCallback } from 'react';

import useHttp from './hooks/use-http';

function App() {
  const [tasks, setTasks] = useState([]);

  // 커스텀 훅에 인자를 연결하고 
  // 응답을 가져오는 시점에 구조를 분해해서 받아옴
  // sendRequest 함수의 fetchTasks 별칭을 달아줌
  const { isLoading, error, sendRequest: fetchTasks } = useHttp();

  useEffect(() => {
    // firebase에서 받아온 데이터를 가공하는 함수임
    // 랜덤으로 키값을 생성하기 때문에 가공이 이렇게 까다로워짐
    // 응답 오는 데이터에 알맞게 각자 가공해주면 됨
    const transformTasks = (tasksObj) => {
      const loadedTasks = [];

      for (const taskKey in taskObj) {
        loadedTasks.push({ id: taskKey, text: taskObj[taskKey].texy });
      }

      setTasks(loadedTasks);
    };
    fetchTasks({ url: 'http://어쩌구저쩌구' }, transformTasks);
  }, [fetchTasks]);

  return (
    <React.Fragment>
      <!--Tasks 컴퍼넌트에 커스텀 훅을 통해 받은 내용들은 내려줌-->
      <Tasks 
        items={tasks}
        loading={isLoading}
        error={error}
        onFetch={fetchTasks}
      />
    </React.Fragment>

  );
}


export default App;

 

  • 커스텀 훅을 연결하고 받아오는 데이터를 가공하여 Tasks 컴퍼넌트에 내려줍니다.
  • 기본적으로 GET이기 때문에 requestConfig가 심플하게 끝납니다.

 

다음으로 POST 요청도 구성해 보겠습니다.

 

NewTask.js

import { useState } from "react";

import useHttp from "./hooks/use-http";

const NewTask = (props) => {
    const { isLoading, error, sendRequest: sendTaskRequest } = useHttp();

    const createTask = (taskText, taskData) => {
        const generatedId = taskData.name;
        const createdTask = { id: generatedId, text: taskText };

        // 설명은 빠졌지만 APP에서 간단히 기존의 task에 합치는 함수
        props.onAddTask(createTask);
    }

    const enterTaskHandler = async (taskText) => {
        sendTaskRequest(
            {
                url: 'http://어쩌구저쩌구',
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: { text: taskText }
            },
            // createTask를 바인딩 하여 createTask 함수에서 taskText를 쓸 수 있게 함
            createTask.bind(null, taskText));
    }
}

...

 

  • POST 요청은 일반적으로 화면을 리렌더링 하는 게 없기에 useEffect를 사용할 필요가 없습니다.
  • bind 메서드를 이용하여 enterTaskHandler 함수를 호출 즉시가 아닌 사전에 구성할 수 있게 합니다.

 

'REACT' 카테고리의 다른 글

useContext 훅  (5) 2023.03.03
useReducer 훅  (5) 2023.03.02
커스텀 훅(Custom Hook)  (10) 2023.02.16
리액트 최적화 테크닉  (7) 2023.02.14
HTTP 요청 보내기  (8) 2023.02.13