diff --git a/src/components/atoms/ReceiptQuotes/ReceiptQuotes.jsx b/src/components/atoms/ReceiptQuotes/ReceiptQuotes.jsx index 8ce7899..6db98da 100644 --- a/src/components/atoms/ReceiptQuotes/ReceiptQuotes.jsx +++ b/src/components/atoms/ReceiptQuotes/ReceiptQuotes.jsx @@ -1,5 +1,5 @@ -import { useEffect, useState } from "react"; import * as S from "./ReceiptQuotes.styles"; +import useAsync from "../../../hooks/useAsync"; /** * ReceiptQuotes @@ -10,18 +10,17 @@ import * as S from "./ReceiptQuotes.styles"; * @returns */ export function ReceiptQuotes() { - const [quotesState, setQuotes] = useState(); + const [state] = useAsync(getQuotes, []); + const { loading, data: quote, error } = state; + console.log(quote); - useEffect(() => { - const getQuotes = async () => { - await fetch("https://api.adviceslip.com/advice") - .then((response) => response.json()) - .then((data) => setQuotes(data.slip.advice)) - .catch((e) => console.error(e)); - }; + return {loading || error ? "Well done!" : quote}; +} - getQuotes(); - }, []); +async function getQuotes() { + const response = await fetch("https://api.adviceslip.com/advice").then((response) => + response.json(), + ); - return {quotesState || "Well done!"}; + return response.slip.advice; } diff --git a/src/hooks/useAsync.jsx b/src/hooks/useAsync.jsx new file mode 100644 index 0000000..e4be0c2 --- /dev/null +++ b/src/hooks/useAsync.jsx @@ -0,0 +1,54 @@ +// 참고 자료 - https://react.vlpt.us/integrate-api/03-useAsync.html + +import { useReducer, useEffect } from "react"; + +function reducer(state, action) { + switch (action.type) { + case "LOADING": + return { + loading: true, + data: null, + error: null, + }; + case "SUCCESS": + return { + loading: false, + data: action.data, + error: null, + }; + case "ERROR": + return { + loading: false, + data: null, + error: action.error, + }; + default: + throw new Error(`Unhandled action type: ${action.type}`); + } +} + +function useAsync(callback, deps = []) { + const [state, dispatch] = useReducer(reducer, { + loading: false, + data: null, + error: false, + }); + + const fetchData = async () => { + dispatch({ type: "LOADING" }); + try { + const data = await callback(); + dispatch({ type: "SUCCESS", data }); + } catch (e) { + dispatch({ type: "ERROR", error: e }); + } + }; + + useEffect(() => { + fetchData(); + }, deps); + + return [state, fetchData]; +} + +export default useAsync;