hooks API로 만든 useFetch 코딩 리뷰 신청

안녕하새요, 코드리뷰 신청합니다.

fetch API를 이용해서 ‘GET’ 그리고 'POST’를 할 수 있는 custom hooks를 만들어봤습니다.

사용법 :

const { data: fetchData = [], loading: fetchLoading, error: fetchError } = useFetch('/url');
const { data: postData, loading: postLoading, error: postError, post } = useFetch('/url', 'POST');

<DisplayData={fetchData} /// get method
<Button onClick={()=post({id:4, name: 'codeJong'}) /// post method
//useFetch

const useFetch = (url, method) ={
    const [data, setData] = useState([]);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(false);

    if (!url || url.length === 0) {
        console.error('Missing url');
        if (!error) setError(true);
        if (loading) setLoading(false);
        return { data, loading, error };
    }

    const runFetchProcess = async (data) ={
        const requestMethod = method === 'POST' ? 'POST' : 'GET';
        let requestHeader = {
            headers: {
                'Content-Type': 'application/json',
            },
            method: requestMethod,
        };

        if (data) {
            requestHeader.body = JSON.stringify(data);
        }

        try {
            const response = await fetch(url, requestHeader);
            const responseData = await response?.json();
            if (!response.ok) {
                setLoading(false);
                setError(true);
                throw Error('something wrong here mate');
            } else {
                setData(responseData);
                setLoading(false);
            }
        } catch (e) {
            setError(true);
            console.error('useFetch.js', e);
        } finally {
            setLoading(false);
        }
    };

    const post = (data) ={
        if (!data) return;
        runFetchProcess(data);
    };

    useEffect(() ={
        if (method) return;
        runFetchProcess();
    }, []);

    return { data, loading, error, post };
};

export default useFetch;

좋은 리뷰 기대할깨요 :slight_smile: 감사합니다.
꾸벅

안녕하세요~! 반갑습니다. :raised_hand:

우선 첨부하신 코드를 markdown의 코드 넣을 때 방식을 이용해서 이쁘게 보이도록 본문을 수정했습니다
사용하신 > 는 인용을 나타낼 때 사용하는 포멧이고 코드의 경우 ``` 를 맨 첫줄과 맨 마지막 줄에 붙이면 여러줄의 코드가 이쁘게 첨부됩니다. (참고)

우선 코드를 살펴보니 의도하신 동작이 useFetch를 사용할 때 url만 넣으면 자동으로 fetch가 되는 방식을 사용하셨네요.

자동으로 fetch 된다는 의도하신 것에서 크기 벗어나지 않는 선에서 실질적인 구현보다는 입력 출력이라는 관점에서 어떻게 동작하게하는지 좋은지를 이야기해보겠습니다.

입력과 출력의 관계

useFetch에게

  1. 입력 : method와 url을 넘겨서
  2. 출력 : 해당 API를 호출한 결과를 데이터를 받고자 했습니다.

입력이 바뀌면 출력이 바뀌는게 선언적 프로그래밍을 추구하는 리액트에서 더욱 자연스럽습니다. 따라서 useFetch 에 넘기는 인자인 url이나 method가 바뀌면 그 return 값이 (비동기적 결과 포함) 달라질 수 있는 형태가 좋겠습니다.

예를 들어 첨부해주신 코드는 url이 도중에 바뀌어도 useFetch 내부에서 자동으로 다시 데이터를 가져오지 않습니

첫 렌더링 시 fetch와 추가 렌더링시 fetch

post일 경우는 첫 렌더링시에 runFetchProcess를 하지 않으려고 useEffect 에서 if(method) return;을 한 것이죠? 이는 post나 get이나에 따라 다른 동작을 하게 하기보다는 첫 렌더링을 할지 말지를 별도의 option으로 지정하는게 좋을 것 같습니다. 그래야 이 custom Hook을 사용하는 사람이 useFetch의 구현을 살펴볼 필요 없이 입력 출력만 보고 어떤 동작을 하는지 더 쉽게 파악하게 됩니다.

const { data: fetchData = [], loading: fetchLoading, error: fetchError } = useFetch('/url', null, {
  someOption: true,
  someOption2: false
});

딱 내 구미에 맞는 걸 찾지 못하거 공부할 목적으로 custom hook이나 component를 만들고자 할 경우 모두 가장 유사한 라이브러리를 찾아보고 그 hook이나 component의 입력과 출력을 기준으로 잘 살펴보시는 것이 저에게는 많은 도움이 되었어요. 따라서 지금 만들고자 하는 useFetch의 경우 react-query를 한번 살펴보시면 많은 도움이 될 것 같습니다. (참고로 저는 요즘 graphql을 relay를 이용해서 쓰고 있다보니 react-query를 쓰지는 않습니다. 전에 react query 비슷한 목적으로 간단히 만들고 썼던 useRequest라는 코드가 있긴 한데 부족한 점도 있고 저도 지금은 안쓰고 있어요. 참고차 공유해봅니다.)

도움이 되길 바랍니다.ㅎ 오늘도 즐거운 코딩하세요~ :grin:

:+1:

:+1:

SWR 라이브러리도 괜찮게 보고 있습니다.
감사합니다. :pray: