[TIL] 0615 | React with Redux, Next.js, TypeScript

Teasanยท2022๋…„ 6์›” 14์ผ
0

TIL

๋ชฉ๋ก ๋ณด๊ธฐ
8/36
post-thumbnail

๋ชฉ์ฐจ

  • ์ข€ ๋” ํ˜„์‹ค์ ์ธ ์˜ˆ์‹œ๋ฅผ ์œ„ํ•ด
  • ์‚ฌ์šฉ์ž ์ •์˜ Http ํ›… ๋นŒ๋“œํ•˜๊ธฐ
  • ์‚ฌ์šฉ์ž ์ •์˜ Http ํ›… ์‚ฌ์šฉํ•˜๊ธฐ

โœง ์ข€ ๋” ํ˜„์‹ค์ ์ธ ์˜ˆ์‹œ๋ฅผ ์œ„ํ•ด

  • ๋จผ์ € ์ด์ „์— HTTP ์š”์ฒญ์„ ์ „์†กํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ๋ฐฉ๋ฒ•์„ ํ•™์Šตํ•œ ์ ์ด ์žˆ์„ ๊ฒƒ์ด๋‹ค. ์ด๋•Œ ์‚ฌ์šฉํ–ˆ๋˜ Firebase์˜ realtime database์˜ URL ์ฃผ์†Œ๊ฐ€ ํ•„์š”ํ•˜๋‹ˆ, ๊ทธ ์ฃผ์†Œ๋ฅผ ๊ธ์–ด์™€ ํ˜„์žฌ์˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ fetch๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” URL ์ฃผ์†Œ๋ฅผ ๋Œ€์ฒดํ•˜๋„๋ก ํ•˜์ž. ๋ฌผ๋ก  Firebase ๊ฐ€ ์š”๊ตฌํ•˜๋Š” ์กฐ๊ฑด /์ €์žฅํ•˜๊ณ ์ž ํ•˜๋Š” ๋…ธ๋“œ์˜ ์ด๋ฆ„.json์„ URL ์ฃผ์†Œ ๋’ค์— ๋ถ™์ด๋Š” ๊ฑธ ์žŠ์ง€ ๋ง์ž.

  • ์ด ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์–ด๋–ป๊ฒŒ ๋Œ์•„๊ฐˆ๊นŒ? ๋จผ์ € URL์„ Firebase์˜ realtime database์˜ URL ์ฃผ์†Œ๋กœ ์ˆ˜์ •ํ•ด์ฃผ๊ณ  ์ €์žฅํ•œ ๋’ค, ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•ด๋ณด์ž.

  • "Task 1"์„ ์ถ”๊ฐ€ํ•˜๊ณ  "Add Button"์„ ๋ˆ„๋ฅธ ๋’ค ์—ฐ๊ฒฐํ•œ Firebase์˜ realtime database ๋กœ ์ด๋™ํ•˜๋ฉด

  • ๋‚ด๊ฐ€ ์„ค์ •ํ•œ ์ƒˆ๋กœ์šด ๋…ธ๋“œ(tasks)๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ปค์Šคํ…€ ํ›…์œผ๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋Š” ๊ณตํ†ต๋œ ๋กœ์ง ์ฐพ์•„๋ณด๊ธฐ

  • ํ˜„์žฌ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฐ์ดํ„ฐ(Task)๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ ๋กœ์ง๋“ค์„ ๋ณด๋ฉด Task ๋ฐ์ดํ„ฐ๋ฅผ fetch API ๋ฅผ ํ†ตํ•ด Firebase์˜ database์— "POST" ํ•˜๊ณ , ์ด๋ฅผ ๋‹ค์‹œ "GET" ํ•ด์˜ค๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•œ ๊ฑธ ์•Œ ์ˆ˜ ์žˆ๋‹ค. HTTP ๋ฅผ ์ „์†กํ•˜๊ณ  ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ๋กœ๋”ฉ ์ƒํƒœ(state)๋„ ๊ด€๋ฆฌํ•˜๋ฉฐ ๋„์ฐฉํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ํ‘œ์‹œํ•˜๋Š” ๋ชจ๋“  ์ž‘์—…์ด fetch API๋ฅผ ํ†ตํ•ด ์ด๋ฃจ์–ด์ง„ ๊ฒƒ์ด๋‹ค. ์—ฌ๊ธฐ์—๋Š” ๋‹ค์–‘ํ•œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ด€๋ฆฌํ•ด์ฃผ๊ณ  ์žˆ์ง€๋งŒ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ฒƒ์€ App ์ปดํฌ๋„ŒํŠธ๋กœ Task ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” fetchTask ํ•จ์ˆ˜๊ฐ€ ์žˆ๋Š” ๋ถ€๋ถ„์ด๋‹ค.

App.js

const fetchTasks = async (taskText) => {
  setIsLoading(true);
  setError(null);
  try {
    const response = await fetch(
      "https://react-http-6b4a6.firebaseio.com/tasks.json"
    );

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

    const data = await response.json();

    const loadedTasks = [];

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

    setTasks(loadedTasks);
  } catch (err) {
    setError(err.message || "Something went wrong!");
  }
  setIsLoading(false);
};
  • ์ด fetchTasks ํ•จ์ˆ˜๋Š” useEffect๋กœ ์ธํ•ด ์‹คํ–‰๋˜๊ฑฐ๋‚˜ App ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” Tasks ์ปดํฌ๋„ŒํŠธ์— props๋กœ ์ „๋‹ฌ๋˜์–ด ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ๋ฒ„ํŠผ์ด ํด๋ฆญ๋˜๊ฑฐ๋‚˜ ํ•˜๋ฉด์„œ ์‹คํ–‰๋˜๊ณ  ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ App ์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ fetchTasks ํ•จ์ˆ˜๊ฐ€ ํŠธ๋ฆฌ๊ฑฐ ๋˜๊ณ  ์žˆ๋‹ค.

NewTask.js

const enterTaskHandler = async (taskText) => {
  setIsLoading(true);
  setError(null);
  try {
    const response = await fetch(
      "https://react-http-6b4a6.firebaseio.com/tasks.json",
      {
        method: "POST",
        body: JSON.stringify({ text: taskText }),
        headers: {
          "Content-Type": "application/json",
        },
      }
    );

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

    const data = await response.json();

    const generatedId = data.name; // firebase-specific => "name" contains generated id
    const createdTask = { id: generatedId, text: taskText };

    props.onAddTask(createdTask);
  } catch (err) {
    setError(err.message || "Something went wrong!");
  }
  setIsLoading(false);
};
  • NewTask ์ปดํฌ๋„ŒํŠธ๋„ fetch API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋กœ์ง ํ•จ์ˆ˜ enterTaskHandler ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. enterTaskHandler ํ•จ์ˆ˜๋Š” App์˜ fetchTasks ํ•จ์ˆ˜์ฒ˜๋Ÿผ HTTP ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์žˆ์ง€๋งŒ, Firebase์— ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ "POST" ์š”์ฒญ์ด ์ „์†ก๋œ๋‹ค. ์ด enterTaskHandler ํ•จ์ˆ˜๋Š” TaskForm ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ตœ์ข…์ ์œผ๋กœ ์ œ์ถœ๋  ๋•Œ ํŠธ๋ฆฌ๊ฑฐ ๋˜๋Š” ํ•จ์ˆ˜์ด๋‹ค. ์ฆ‰, TaskForm ์ปดํฌ๋„ŒํŠธ๋Š” NewTask ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ props๋กœ ํ•จ์ˆ˜๋ฅผ ๋ฐ›์•„ ํ•ด๋‹น ํ•จ์ˆ˜์—์„œ ๋ฒ„ํŠผ์ด ํด๋ฆญ๋˜๊ฑฐ๋‚˜ ์ธํ’‹์— ์ž…๋ ฅ๋œ ๊ฐ’์ด ๊ฒ€์ฆ๋˜๋Š” ์‹œ์ ์—์„œ enterTaskHandler๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ด๋‹ค.

์ •๋ฆฌ

  • ์ด ๋‘๊ฐ€์ง€์˜ ์ปดํฌ๋„ŒํŠธ(App, NewTask)๋ฅผ ์‚ดํŽด๋ณด๋ฉด์„œ, fetch API๋ฅผ ์‚ฌ์šฉํ•ด์„œ HTTP ์š”์ฒญ์„ ํ•˜๋Š” ๋กœ์ง์ด ์ตœ์†Œ ํ•˜๋‚˜ ์ด์ƒ์˜ ์ปค์Šคํ…€ ํ›…์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฑธ ์•Œ ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์ด ๋‘๊ฐœ์˜ HTTP ์š”์ฒญ์„ ํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ๋ชจ๋‘ ๋™์ผํ•œ ๋กœ์ง์„ ๊ฐ€์ง„ ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€์˜ ๋น„์Šทํ•œ ์ข…๋ฅ˜์˜ ์ž‘์—…์„ ํ•˜๊ณ  ์žˆ์„ ๊ฒƒ์ด๋‹ค. ์ €์žฅํ•  ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๋Š” ๋ถ€๋ถ„๊ณผ, ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•œ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๋ถ€๋ถ„ ๋ง์ด๋‹ค. ์„ธ๋ฐ€ํ•˜๊ฒŒ ์‚ดํŽด๋ณด๋ฉด ์‘๋‹ต์— ๋Œ€ํ•œ ๋ณ€ํ™˜ ๋กœ์ง์€ ์กฐ๊ธˆ ๋‹ค๋ฅธ ํ˜•ํƒœ์ด์ง€๋งŒ ์‹ค์ œ๋กœ ์ฝ”๋“œ๊ฐ€ ์œ ์‚ฌํ•œ ๋ถ€๋ถ„์€ ์ƒ๋‹น์ˆ˜ ์กด์žฌํ•œ๋‹ค. ๋กœ๋”ฉ๊ณผ ์˜ค๋ฅ˜ ์ƒํƒœ(state)๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ์„ค์ •ํ•˜๋Š” ๊ฒƒ๊ณผ ์˜ค๋ฅ˜๋ฅผ ๋‹ค๋ฃจ๋Š” ๋กœ์ง ์—ญ์‹œ ๋™์ผํ•˜๋‹ค. ์ด์ฒ˜๋Ÿผ ๋น„์Šทํ•œ ์ฝ”๋“œ๊ฐ€ ์กด์žฌํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ถ€๋ถ„์˜ ๋กœ์ง์„ ๋ณ„๋„์˜ ํ•จ์ˆ˜์— ์•„์›ƒ์†Œ์‹ฑํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด๋ณผ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค. ์ง€๊ธˆ๊นŒ์ง€ ๋ฐฐ์šด ์ปค์Šคํ…€ ํ›…์„ ํ†ตํ•ด์„œ ๋ง์ด๋‹ค.

โœง ์‚ฌ์šฉ์ž ์ •์˜ Http ํ›… ๋นŒ๋“œํ•˜๊ธฐ

  • hooks ํด๋”๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‚ฌ์šฉํ•  ์ปค์Šคํ…€ ํ›… use-fetch.js ํŒŒ์ผ์„ ๋งŒ๋“ ๋‹ค.
const useFetch = () => {};
export default useFetch;
  • ๊ทธ๋ฆฌ๊ณ  ๋จผ์ € useFetch ์ปค์Šคํ…€ ํ›…์œผ๋กœ ์•„์›ƒ์†Œ์‹ฑํ•  ๋กœ์ง(App.js)์„ ํ™•์ธํ•œ๋‹ค.

App.js

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

const fetchTasks = async (taskText) => {
  setIsLoading(true);
  setError(null);
  try {
    const response = await fetch(
      "https://react-http-6b4a6.firebaseio.com/tasks.json"
    );

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

    const data = await response.json();

    const loadedTasks = [];

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

    setTasks(loadedTasks);
  } catch (err) {
    setError(err.message || "Something went wrong!");
  }
  setIsLoading(false);
};
  • ์œ„์˜ ๋กœ์ง๋“ค์„ ์‚ดํŽด๋ณด๋ฉด, ์ด๊ฒƒ์€ ๋กœ๋”ฉ๊ณผ ์˜ค๋ฅ˜ ์ƒํƒœ(state)์— ๋Œ€ํ•œ ๊ฒƒ์ž„๊ณผ ๋™์‹œ์— ์‘๋‹ต์„ ๋ณด๋‚ด๊ณ  ํ•ด๋‹น ์‘๋‹ต์„ ํ‰๊ฐ€ํ•˜๋Š” ์ฝ”๋“œ์ด๊ธฐ๋„ ํ•œ ๊ฑธ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ๋ชจ๋‘๊ฐ€ ์•„์›ƒ์†Œ์‹ฑ ๋˜์–ด์•ผ ํ•œ๋‹ค. ํ•ด๋‹น fetchTasks ํ•จ์ˆ˜ ์ „์ฒด์™€ isLoading, error ์˜ ์ƒํƒœ(state) ์ฝ”๋“œ๊นŒ์ง€ ๋ชจ๋‘ ๋ณต์‚ฌํ•ด์„œ useFetch ์ปค์Šคํ…€ ํ›… ํ•จ์ˆ˜ ์•ˆ์— ๋ถ™์—ฌ ๋„ฃ์–ด์ค€๋‹ค.
const [tasks, setTasks] = useState([]);

tasks ์ƒํƒœ(state)๋Š” App ์ปดํฌ๋„ŒํŠธ์—๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ์ œ์™ธํ•˜๊ณ  ๋ชจ๋‘ ๋ณต์‚ฌํ•ด์„œ useFetch ์ปค์Šคํ…€ ํ›…์— ๋„ฃ์–ด์ฃผ์ž.

use-fetch.js

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

  const sendRequest = async (taskText) => {
    setIsLoading(true);
    setError(null);
    try {
      const response = await fetch(
        "https://react-http-6b4a6.firebaseio.com/tasks.json"
      );

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

      const data = await response.json();

      const loadedTasks = [];

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

      setTasks(loadedTasks);
    } catch (err) {
      setError(err.message || "Something went wrong!");
    }
    setIsLoading(false);
  };

  return {
    isLoading: isLoading,
    error: error,
    sendRequest: sendRequest,
  };
};
  • App ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ธ์–ด์˜จ fetchTasks ํ•จ์ˆ˜์˜ ์ด๋ฆ„์„ sendRequest๋กœ ์ˆ˜์ •ํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ์ˆ˜์ •ํ•œ๋‹ค๋ฉด ๋‚ด๋ถ€์— ์žˆ๋Š” ๋กœ์ง์„ ์ข€ ๋” ์ผ๋ฐ˜ํ™”์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค. ์ด useFetch ์ปค์Šคํ…€ ํ›…์€ ๋ฐ์ดํ„ฐ fetch ์—๋งŒ ๊ตญํ•œ๋˜์–ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์—ญํ• ๋งŒ ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๋Š” ์—ญํ• ๋„ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์กฐ๊ธˆ ๋” ์ด๋ฆ„์„ ์ผ๋ฐ˜ํ™” ์‹œํ‚ค๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋ ‡๊ฒŒ ์ˆ˜์ •ํ•˜๊ฒŒ ๋˜๋ฉด ํ›…์˜ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ด๊ณ  ์—ฌ๋Ÿฌ ์ž‘์—…์—๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฑธ ๋ช…์‹œ์ ์œผ๋กœ ์•Œ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

useFetch ์ปค์Šคํ…€ ํ›…์— ๋‹ค์ˆ˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ถ”๊ฐ€ํ•˜๊ธฐ

  • useFetch ์ปค์Šคํ…€ ํ›…์€ ์–ด๋–ค ์ข…๋ฅ˜์˜ ์š”์ฒญ์ด๋“  ๋ฐ›์•„์„œ ๋ชจ๋“  ์ข…๋ฅ˜์˜ URL๋กœ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๊ณ , ๋˜ํ•œ ์–ด๋–ค ๋ฐ์ดํ„ฐ๋“  ๋ณ€ํ™˜์„ ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. ๋™์‹œ์— ๋กœ๋”ฉ(isLoading)๊ณผ ์˜ค๋ฅ˜(error) ์ƒํƒœ(state)๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ , ๋ชจ๋“  ๊ณผ์ •์„ ๋™์ผํ•œ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰ํ•ด์•ผ๋งŒ ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๋Ÿฐ ์œ ์—ฐํ•œ ์ปค์Šคํ…€ ํ›…์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ช‡ ๊ฐ€์ง€์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

App.js

const response = await fetch(
  "https://react-http-6b4a6.firebaseio.com/tasks.json"
);

NewTask.js

const response = await fetch(
  "https://react-http-9914f-default-rtdb.firebaseio.com/tasks.json",
  {
    method: "POST",
    body: JSON.stringify({ text: taskText }),
    headers: {
      "Content-Type": "application/json",
    },
  }
);
  • ๋จผ์ €, ์ด fetch API ์˜ response ๋กœ์ง ๋ถ€๋ถ„์„ ๋ณด๋ฉด URL ์„ ๋น„๋กฏํ•˜์—ฌ, ๋ฉ”์†Œ๋“œ, body, headers ๋“ฑ ์œ ์—ฐ์„ฑ์„ ๊ฐ–์ถ”์–ด์•ผ ํ•จ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. NewTask ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋Š” HTTP ์š”์ฒญ์€ "POST"์ด๊ธฐ ๋–„๋ฌธ์— fetch API๋ฅผ ์š”์ฒญํ•  ๋•Œ URL ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ๋‘ ๋ฒˆ์งธ ์ธ์ž์— ๋ฉ”์†Œ๋“œ, body, headers ๊ฐ€ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋”ฐ๋ผ์„œ ํ•ด๋‹น ์„ค์ •์„ ์œ„ํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜(requestConfig)๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
const useFetch = (requestConfig) => {
  ...
}
  • ๋งค๊ฐœ๋ณ€์ˆ˜ requestConfig๋Š” URL์„ ํฌํ•จํ•ด์„œ ์–ด๋–ค ์ข…๋ฅ˜์˜ ์„ค์ • ์‚ฌํ•ญ๋„ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด ํ˜•ํƒœ์—ฌ์•ผ๋งŒ ํ•  ๊ฒƒ์ด๋‹ค.
const sendRequest = async (taskText) => {
  setIsLoading(true);
  setError(null);
  try {
    // โšก๏ธ --------
    const response = await fetch(requestConfig.url, {
      method: requestConfig.method,
      headers: requestConfig.headers,
      body: JSON.stringify(requestConfig.body),
    });
    // โšก๏ธ --------

    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);
};
  • ๋”ฐ๋ผ์„œ URL ์ฃผ์†Œ์™€ ์„ค์ • ๊ฐ์ฒด ๋“ฑ ํ•˜๋“œ ์ฝ”๋”ฉ๋œ ๊ฒƒ์„ ์ œ๊ฑฐํ•œ ๋’ค, URL์€ requestConfig.url ๊ทธ๋ฆฌ๊ณ  ์„ค์ • ๊ฐ์ฒด๋Š” ๊ฐ๊ฐ method๋Š” requestConfig.method, headers๋Š” requestConfig.headers, body๋Š” JSON.stringify(requestConfig.body)๋กœ ํ• ๋‹นํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•ด์•ผ, ์™ธ๋ถ€ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ปค์Šคํ…€ ํ›…์„ ํ˜ธ์ถœํ•  ๋•Œ URL ์ฃผ์†Œ๋ฅผ ๋‹ด์€ ๊ฒƒ๊ณผ ํ•ด๋‹น ์„ค์ • ์†์„ฑ์„ ๊ฐ€์ง„ ๊ฐ์ฒด(requestConfig)๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด๋ ‡๊ฒŒ ๋˜๋ฉด, "GET"์œผ๋กœ URL๋งŒ ์š”์ฒญํ•˜๋Š” ๋กœ์ง ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, "POST"๋กœ ์š”์ฒญํ•  ๋•Œ๋„ ์„ค์ • ๊ฐ์ฒด๋ฅผ ๋„ฃ์–ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.
const data = await response.json();
  • ๋‹น์—ฐํ•˜๊ฒŒ๋„ ์ด๋Ÿฐ ๋ฐฉ์‹์œผ๋กœ response์„ ๋ณ€ํ™˜ํ•˜๊ธฐ๋„ ํ•ด์•ผ ํ•œ๋‹ค. JSON ๋ฐ์ดํ„ฐ๋งŒ์„ ๋‹ค๋ฃฐ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์—, ์ด ๋ถ€๋ถ„์€ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  ๊ทธ๋Œ€๋กœ ๋‘”๋‹ค.
const loadedTasks = [];

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

setTasks(loadedTasks);
  • ํ•˜์ง€๋งŒ ์œ„์˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ ๋ฐ์ดํ„ฐ๋ฅผ ์ตœ์ข…์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ถ€๋ถ„์€ ๋„ˆ๋ฌด ๊ตฌ์ฒด์ ์ธ ๋ถ€๋ถ„(GET ์š”์ฒญ๋งŒ์„ ์œ„ํ•œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ)์ด๊ธฐ ๋•Œ๋ฌธ์— ์ปค์Šคํ…€ ํ›…์— ํฌํ•จ๋˜์„œ๋Š” ์•ˆ๋  ๊ฒƒ์ด๋‹ค. ๋Œ€์‹ ์— ์—ฌ๊ธฐ์— ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋ฉด, useFetch ์ปค์Šคํ…€ ํ›…์„ ์‚ฌ์šฉํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ ์–ป์€ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•ด์„œ ๊ทธ ํ•จ์ˆ˜์— ๋ฐ์ดํ„ฐ๋ฅผ ๋„˜๊ฒจ์ฃผ๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์„ธ๋ถ€์ ์ธ ๋ณ€ํ™˜ ๊ณผ์ •์€ ์ปค์Šคํ…€ ํ›…์ด ์‚ฌ์šฉ๋˜๋Š” ์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ ์ •์˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค. ๋”ฐ๋ผ์„œ ์œ„์˜ ์ฝ”๋“œ๋ฅผ ์ปค์Šคํ…€ ํ›… ๋‚ด๋ถ€์—์„œ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ , ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์€ ํ•จ์ˆ˜๋กœ ์ฒ˜๋ฆฌํ•ด์ค„ ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
const useFetch = (requestConfig, applyData) => {
  ...
}
  • ํ•ด๋‹น ๋กœ์ง(๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ)์„ ์ฒ˜๋ฆฌํ•  ํ•จ์ˆ˜๋ฅผ applyData ๋ผ๋Š” ์ด๋ฆ„์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›๊ธฐ๋กœ ํ•œ๋‹ค. ์š”์ฒญ์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ ๋‹ค์Œ applyData ๋งค๊ฐœ๋ณ€์ˆ˜ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•œ๋‹ค.
const data = await response.json();

applyData(data);
  • ์ฆ‰, useFetch ์ปค์Šคํ…€ ํ›…์—์„œ applyData ํ•จ์ˆ˜๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•œ ๊ฒƒ์ด๋ฉฐ, applyData ํ•จ์ˆ˜ ์•ˆ์—์„œ ๋ฌด์—‡์ด ๋ฐœ์ƒํ•˜๋Š”์ง€์— ๋Œ€ํ•ด์„œ๋Š” applyData ์ปค์Šคํ…€ ํ›…์„ ์‚ฌ์šฉํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์—์„œ ์ •์˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค. ์ด์ œ useFetch ์ปค์Šคํ…€ ํ›…์—์„œ ์žฌ์‚ฌ์šฉ๊ณผ ์žฌ์‚ฌ์šฉ ๋กœ์ง์„ ์ค€๋น„ํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์„ธ๋ถ€์ ์ธ ๊ณผ์ •์€ ํ•ด๋‹น ์ปค์Šคํ…€ ํ›…์„ ์‚ฌ์šฉํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์—์„œ๋งŒ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๋ ‡๊ฒŒ ๋ถ„๋ฆฌ๋ฅผ ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์ด์ „๋ณด๋‹ค๋Š” ์กฐ๊ธˆ ๋” ํ•ฉ๋ฆฌ์ ์œผ๋กœ ๋ณด์ธ๋‹ค. useFetch ์ปค์Šคํ…€ ํ›…์—๋Š” isLoading๊ณผ error ๊ฐ™์€ ์ƒํƒœ(state)์™€ HTTP ํ†ต์‹ ์„ ํ•˜๋Š” sendRequest ํ•จ์ˆ˜๊ฐ€ ํฌํ•จ๋˜์—ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๊ฒƒ๋“ค์€ ๊ฒฐ๊ตญ useFetch ์ปค์Šคํ…€ ํ›…์„ ์‚ฌ์šฉํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์— ํ•„์š”ํ•œ ๊ฒƒ๋“ค์ด๋‹ค.

์ปดํฌ๋„ŒํŠธ์—์„œ ์ปค์Šคํ…€ ํ›…์˜ ์ƒํƒœ(state)์™€ ํ•จ์ˆ˜์— ์ ‘๊ทผํ•˜๊ธฐ

  • useFetch ์ปค์Šคํ…€ ํ›…์„ ์‚ฌ์šฉํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋“ค์€ ๋กœ๋”ฉ(isLoading)๊ณผ ์˜ค๋ฅ˜(error) ์ƒํƒœ์— ๋Œ€ํ•ด ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๊ณ , sendRequest ํ•จ์ˆ˜์—๋„ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ž˜์•ผ์ง€ ํ•ด๋‹น ์ปค์Šคํ…€ ํ›…์„ ์‚ฌ์šฉํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋“ค์ด ์ด๊ฒƒ๋“ค์„ ํ™œ์„ฑํ™”ํ•˜๊ณ  ์š”์ฒญ ๋˜ํ•œ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
const useFetch = (requestConfig, applyData) => {
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);

  const sendRequest = async (taskText) => {
    ...
  };

  return {}
};
  • ๋”ฐ๋ผ์„œ useFetch ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ ๊ฐ€์žฅ ํ•˜๋‹จ์œผ๋กœ ์ด๋™ํ•˜์—ฌ ์™ธ๋ถ€ ์ปดํฌ๋„ŒํŠธ๋“ค์ด ์ ‘๊ทผํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ƒํƒœ(state)์™€ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ด์ „์˜ ํ•™์Šต์—์„œ ์–ธ๊ธ‰ํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ์ปค์Šคํ…€ ํ›…์€ ์ˆซ์ž๋‚˜ ๋ฌธ์ž์—ด, ๋ฐฐ์—ด, ๊ฐ์ฒด ๋“ฑ๊ณผ ๊ฐ™์ด ๋ฌด์—‡์ด๋“  ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฒˆ์—๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๊ฐ’๋“ค์„ ๋ฐ˜ํ™˜ํ•  ์˜ˆ์ •์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์ฒด์˜ ํ˜•ํƒœ๋กœ ๋ฐ˜ํ™˜ํ•  ๊ฒƒ์ด๋‹ค.
return {
  isLoading: isLoading,
  error: error,
  sendRequest: sendRequest,
};
  • ๊ฐ์ฒด ์•ˆ์— ๋ฐ˜ํ™˜ํ•  ์ƒํƒœ(isLoading, error)์™€ ํ•จ์ˆ˜(sendRequest)๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๊ฐ์ฒด์˜ ํ‚ค์™€ ๊ฐ’์—์„œ ์™ผ์ชฝ์˜ ํ‚ค๋Š” ์†์„ฑ์˜ ์ด๋ฆ„์„ ๋งํ•˜๊ณ , ์˜ค๋ฅธ์ชฝ์˜ ๊ฐ’์€ ๋ง ๊ทธ๋Œ€๋กœ ๊ฐ’์„ ์˜๋ฏธํ•œ๋‹ค.
return {
  isLoading,
  error,
  sendRequest,
};
  • ๋ฌผ๋ก , ๊ฐ์ฒด ๋‚ด๋ถ€์˜ ์ขŒ์ธก์˜ ์†์„ฑ ์ด๋ฆ„๊ณผ ์šฐ์ธก์˜ ๊ฐ’์˜ ์ด๋ฆ„์ด ๋™์ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ํŽธ์˜ ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ์ƒ๋žตํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ด์ „์— ์ž‘์„ฑํ–ˆ๋˜ ์ฝ”๋“œ์™€ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ์–ป์œผ๋ฉด์„œ ์ฝ”๋“œ๊ฐ€ ์ข€ ๋” ์งง์•„์ง€๋Š” ํšจ๊ณผ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๋ ‡๊ฒŒ ์ƒ๋žต์„ ํ•˜์—ฌ ์‚ฌ์šฉํ•ด๋„, ์ด์ „์˜ ๊ธด ๋ฌธ๋ฒ•์œผ๋กœ ๋ณ€ํ™˜ํ•œ ๋’ค ์‚ฌ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ„๋‹จํ•˜๊ฒŒ ์ƒ๋žตํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์ข‹์„ ๊ฒƒ์ด๋‹ค.

โœง ์‚ฌ์šฉ์ž ์ •์˜ Http ํ›… ์‚ฌ์šฉํ•˜๊ธฐ

  • ์ด์ œ App ์ปดํฌ๋„ŒํŠธ๋กœ ๋Œ์•„์™€ ์ปค์Šคํ…€ ํ›…(useFetch)์„ ์‚ฌ์šฉํ•ด๋ณด์ž.
import useFetch from "./hooks/use-fetch";
  • ๋จผ์ € ์‚ฌ์šฉํ•  useFetch ํ›…์„ import ํ•ด์˜จ ๋’ค ํ˜ธ์ถœํ•ด์˜ค์ž.
useFetch();
  • ์—ฌ๊ธฐ์—๋Š” ๋‘ ๊ฐœ์˜ ์ธ์ž(๋งค๊ฐœ๋ณ€์ˆ˜)๋ฅผ ์ „๋‹ฌํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. ์ด์ „์— ์šฐ๋ฆฌ๊ฐ€ useFetch์—์„œ ์™ธ๋ถ€ ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ ๋ฐ›๊ธฐ๋กœ ํ•œ ๊ทธ ๋งค๊ฐœ๋ณ€์ˆ˜๋“ค ๋ง์ด๋‹ค.
useFetch(
  {
    url: "https://react-http-9914f-default-rtdb.firebaseio.com/tasks.json",
  },
  ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜
);
  • ๋จผ์ € useFecth ๋‚ด๋ถ€์—์„œ fetch() ์•ˆ์— ๋„ฃ์–ด์ค„ URL๊ณผ method, headers, body ๋“ฑ์˜ ์†์„ฑ์„ ํฌํ•จํ•˜๊ณ  ์žˆ๋Š” requestConfig ์— ๋ณด๋‚ผ ๊ฐ์ฒด์™€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•ด์ฃผ๋Š” ํ•จ์ˆ˜(applyData)๋ฅผ ์ „๋‹ฌํ•ด์•ผ ํ•œ๋‹ค. requestConfig ์— ๋ณด๋‚ด๋Š” ๊ฐ์ฒด๋Š” ๋‚ด๋ถ€์— ํ•„์š”ํ•œ ์†์„ฑ๋“ค์ด ํฌํ•จ๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์ปค์Šคํ…€ ํ›… ๋‚ด๋ถ€์—์„œ URL ๊ณผ method, headers, body ๋“ฑ์˜ ์†์„ฑ์— ์ ‘๊ทผํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋”ฐ๋ผ์„œ App ์ปดํฌ๋„ŒํŠธ์˜ url ์†์„ฑ์— ํ•ด๋‹น ๋ฌธ์ž์—ด ์ฃผ์†Œ๋ฅผ ํ• ๋‹นํ•ด์ค€๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ๋‚˜๋จธ์ง€ method, headers, body ์†์„ฑ์€ ์™œ ๋„ฃ์–ด์ฃผ์ง€ ์•Š์„๊นŒ?

App ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ requestConfig์— ๋ณด๋‚ด๋Š” ๊ฐ์ฒด์—๋Š” ์™œ URL ๋งŒ ํฌํ•จ์‹œ์ผฐ์„๊นŒ

  • useFetch ์ปค์Šคํ…€ ํ›…์„ ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•˜๋Š” ๋‘๊ฐœ์˜ ์ปดํฌ๋„ŒํŠธ์˜ ์ฐจ์ด์ ์„ ํ™•์ธํ•ด๋ณด์ž. App ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ทธ์ € ๊ฐ€์ ธ์˜ค๊ธฐ๋งŒ ํ•˜๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ์— "GET" ์š”์ฒญ์œผ๋กœ๋งŒ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ณ , ์—ฌ๊ธฐ์—๋Š” method, headers, body ๋“ฑ์ด ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค. ๋ฐ˜๋ฉด, NewTask ์ปดํฌ๋„ŒํŠธ๋Š” "POST" ์š”์ฒญ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์„œ๋ฒ„์— ๋ณด๋‚ด์•ผ ํ•˜๊ณ  ์—ฌ๊ธฐ์—๋Š” method, headers, body ์˜ ์†์„ฑ์ด ํ•„์š”ํ•˜๋‹ค. ์ด๋ ‡๊ฒŒ ํ•„์š”ํ•œ ์†์„ฑ๋“ค์ด ๋‹ค๋ฅด๊ธฐ ๋–„๋ฌธ์— ์šฐ๋ฆฌ๋Š” ์œ ์—ฐ์„ฑ์„ ์กฐ๊ธˆ ๋” ๊ฐ–์ถฐ์•ผํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค. ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋”๋ฏธ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ผ ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด์ œ ๋‹ค์‹œ ์ปค์Šคํ…€ ํ›…์œผ๋กœ ๋Œ์•„๊ฐ€ fetch()์˜ Request ๋ถ€๋ถ„์„ ์œ ์—ฐ์„ฑ์„ ๊ฐ–์ถ˜ ๋กœ์ง์œผ๋กœ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค.

์ปค์Šคํ…€ ํ›…์˜ fetch() ๋‘ ๋ฒˆ์งธ ์†์„ฑ์— ์œ ์—ฐ์„ฑ ๋ถ€์—ฌํ•˜๊ธฐ

const response = await fetch(requestConfig.url, {
  method: requestConfig.method,
  headers: requestConfig.headers,
  body: JSON.stringify(requestConfig.body),
});
  • useFetch ์ปค์Šคํ…€ ํ›…์œผ๋กœ ๋Œ์•„์™€ response ๋ณ€์ˆ˜์˜ fetch() ๋กœ์ง์„ ์ˆ˜์ •ํ•œ๋‹ค.
const response = await fetch(requestConfig.url, {
  method: requestConfig.method ? requestConfig.method : "GET",
  headers: requestConfig.headers ? requestConfig.headers : {},
  body: JSON.stringify(requestConfig.body)
    ? JSON.stringify(requestConfig.body)
    : null,
});
  • method์˜ ๊ฒฝ์šฐ์—๋Š” requestConfig.method๊ฐ€ ์ ์šฉ ๋˜์—ˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•˜๊ณ (?) ์„ค์ •๋˜์—ˆ์„ ๋•Œ๋งŒ requestConfig.method๋ฅผ ๋ถ€์—ฌํ•˜๊ณ  ์•„๋‹ ๋•Œ(:)๋Š” "GET"์œผ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋„๋ก ์ˆ˜์ •ํ•œ๋‹ค.
  • headers์˜ ๊ฒฝ์šฐ์—๋Š” requestConfig.headers๊ฐ€ ์ ์šฉ ๋˜์—ˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•˜๊ณ (?) ์„ค์ •๋˜์—ˆ์„ ๋•Œ๋งŒ requestConfig.headers๋ฅผ ๋ถ€์—ฌํ•˜๊ณ  ์•„๋‹ ๋•Œ(:)๋Š” ๋นˆ ๊ฐ์ฒด({})๋ฅผ ํ• ๋‹นํ•œ๋‹ค.
  • body์˜ ๊ฒฝ์šฐ์—๋Š” JSON.stringify(requestConfig.body)์˜ ์„ค์ • ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๊ณ (?) ์„ค์ •๋˜์—ˆ์„ ๋•Œ๋งŒ JSON.stringify(requestConfig.body)๋ฅผ ๋ถ€์—ฌํ•˜๊ณ  ์•„๋‹ ๋•Œ(:)๋Š” null๋กœ ํ• ๋‹นํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ์ˆ˜์ •ํ•จ์œผ๋กœ์จ ์ปค์Šคํ…€ ํ›…์€ ์ถฉ๋ถ„ํ•œ ์œ ์—ฐ์„ฑ์„ ๊ฐ–์ถ”๊ฒŒ ๋˜์—ˆ๋‹ค.
useFetch(
  {
    url: "https://react-http-9914f-default-rtdb.firebaseio.com/tasks.json",
  },
  ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜
);
  • ๋‹ค์‹œ App ์ปดํฌ๋„ŒํŠธ๋กœ ๋Œ์•„์˜ค์ž. ์ด์ œ App ์ปดํฌ๋„ŒํŠธ์—์„œ ํ˜ธ์ถœํ•œ useFetch๊ฐ€ ์ด๋Ÿฐ ํ˜•ํƒœ์˜ ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค. ๊ฐ€๋…์„ฑ์„ ์œ„ํ•ด ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๋กœ์ง์„ useFetch ์œ„์— ์ž‘์„ฑํ•œ๋‹ค. ์ด์ œ ๋‚จ์€ ๊ฑด ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•จ์ˆ˜์ธ ๋‘ ๋ฒˆ์งธ ์ธ์ž๋ฅผ ์ค€๋น„ํ•˜๋Š” ์ผ์ด๋‹ค.
const transformTasks = (taskObj) => {};

useFetch(
  {
    url: "https://react-http-9914f-default-rtdb.firebaseio.com/tasks.json",
  },
  transformTasks
);
  • ๋จผ์ € ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋ฅผ ๋‹ด๋‹นํ•  ํ•จ์ˆ˜์˜ ์ด๋ฆ„์„ transformTasks ๋ผ๊ณ  ํ•œ๋‹ค. ์—ฌ๊ธฐ์—๋Š” taskObj๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›๋Š”๋‹ค. ์ด transformTasks ํ•จ์ˆ˜ ๋‚ด๋ถ€์— useFetch ์•ˆ์—์„œ ์‚ฌ์šฉํ–ˆ๋˜ ์ฆ‰, ์ด์ „์— ์ œ๊ฑฐํ–ˆ๋˜ ๊ทธ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๋กœ์ง์„ ๊ทธ๋Œ€๋กœ ๋ณต์‚ฌํ•ด์„œ ๋ถ™์—ฌ๋„ฃ๊ธฐ ํ•ด์ค€๋‹ค.
const transformTasks = (taskObj) => {
  const loadedTasks = [];

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

  setTasks(loadedTasks);
};
  • ๊ทธ๋ฆฌ๊ณ  ์—ฌ๊ธฐ์—์„œ taskObj ์ธ์ž๋ฅผ data ๋กœ ํ‘œ๊ธฐ๋œ ์ž๋ฆฌ์— ๋Œ€์‹  ๋„ฃ์–ด์ฃผ๊ณ ,
const transformTasks = (taskObj) => {
  const loadedTasks = [];

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

  setTasks(loadedTasks);
};
  • for in ๋ฌธ์„ ํ†ตํ•ด์„œ ์ฝ์–ด์™€์„œ ๊ฐ์ฒด ํ˜•ํƒœ๋กœ loadedTasks ์ด๋ผ๋Š” ๋นˆ ๋ฐฐ์—ด์— push ํ•ด์ค€๋‹ค. ์ด์ œ Firebase์—์„œ ๋ฐ›๋Š” ๊ฐ์ฒด์˜ ๋ชจ๋“  ์ž‘์—…์€ ํ”„๋ก ํŠธ์—”๋“œ์—์„œ ํ•„์š”ํ•œ ๊ตฌ์กฐ์™€ ์œ ํ˜•์„ ๊ฐ–๋Š” ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜๋  ๊ฒƒ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  setTasks ์ƒํƒœ(state) ์—…๋ฐ์ดํŠธ ํ•จ์ˆ˜์— ์ „๋‹ฌํ•œ๋‹ค. ์ด๊ฒƒ์œผ๋กœ useFetch() ์˜ ๋‘ ๋ฒˆ์งธ ์ธ์ž์ธ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜๊ฐ€ ์ค€๋น„๋˜์—ˆ๋‹ค.
useFetch(
  {
    url: "https://react-http-9914f-default-rtdb.firebaseio.com/tasks.json",
  },
  transformTasks
);
  • transformTasks ์ด ํ•จ์ˆ˜๋Š” ์ปค์Šคํ…€ ํ›…์ด ์‘๋‹ต์„ ๋ฐ›๊ฒŒ ๋˜๋ฉด ์•Œ์•„์„œ ํ˜ธ์ถœ๋  ๊ฒƒ์ด๋‹ค. ์ด๋Ÿฐ ๋ฐฉ๋ฒ•์ด ์ข‹์€ ์ด์œ ๋Š” ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ฃผ์š” ๋กœ์ง์€ ์ปค์Šคํ…€ ํ›…์— ์•„์›ƒ์†Œ์‹ฑ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๊ณ  ๋กœ์ง์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋Š” ๊ทธ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ์— ์œ„์น˜ํ•˜๊ฒŒ ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

useFetch ์š”์ฒญ ํ™œ์„ฑํ™”ํ•˜๊ธฐ

  • useFetch ์ปค์Šคํ…€ ํ›…์€ ๋งค๊ฐœ๋ณ€์ˆ˜๋งŒ ๋ฐ›๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ฌด์–ธ๊ฐ€๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ๋„ ํ•œ๋‹ค. isLoading๊ณผ error ์ƒํƒœ(state)๊ฐ€ ์žˆ๋Š” ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, sendRequest ํ•จ์ˆ˜์˜ ํฌ์ธํ„ฐ ์—ญ์‹œ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  useFetch ์š”์ฒญ์„ ํ™œ์„ฑํ™”ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ํ˜ธ์ถœ์ด ํ•„์š”ํ•˜๋‹ค. ๋”ฐ๋ผ์„œ App ์ปดํฌ๋„ŒํŠธ์—์„œ httpData๋ž€ ์ด๋ฆ„์œผ๋กœ useFetch๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ณ ,
const httpData = useFetch(
  {
    url: "https://react-http-9914f-default-rtdb.firebaseio.com/tasks.json",
  },
  transformTasks
);
  • ์ด์ œ httpData๋ฅผ ํฌ์ธํ„ฐํ•ด์„œ ๊ตฌ์กฐ๋ฅผ ๋ถ„ํ•ดํ•˜๋Š” ๋กœ์ง์„ ์ž‘์„ฑํ•œ๋‹ค.
const httpData = useFetch(
  {
    url: "https://react-http-9914f-default-rtdb.firebaseio.com/tasks.json",
  },
  transformTasks
);
const {} = httpData;
  • ๊ทธ๋ฆฌ๊ณ  isLoading, error, sendRequest๋ฅผ ๊ฐ์ฒด ๊ตฌ์กฐ ๋ถ„ํ•ด ํ• ๋‹น์„ ํ†ตํ•ด ์ถ”์ถœํ•œ๋‹ค.
const { isLoading, error, sendRequest } = httpData;
  • ๊ทธ๋ฆฌ๊ณ  ์—ฌ๊ธฐ์—์„œ App ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•  ๋ณ„์นญ์„ ์ƒ์„ฑํ•  ๊ฒƒ์ธ๋ฐ, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์ด ๋ถ„ํ•ด ๋ฌธ๋ฒ•์— ์ฝœ๋ก (:)์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋‹ค๋ฅธ ์ด๋ฆ„์„ ๋ถ€์—ฌํ•  ์ˆ˜ ์žˆ๊ธฐ์— ์ด ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ด์„œ ์ƒˆ๋กœ์šด ์ด๋ฆ„์„ ๋ถ€์—ฌํ•œ๋‹ค.
const { isLoading, error, sendRequest: fetchTasks } = httpData;
  • sendRequest์˜ ์ƒˆ๋กœ์šด ์ด๋ฆ„์œผ๋กœ fetchTasks๋ฅผ ์„ค์ •ํ•œ๋‹ค. ์ด๋Š” ์ปค์Šคํ…€ ํ›… ๋‚ด๋ถ€์˜ sendRequest ํ•จ์ˆ˜๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋Š” ํฌ์ธํ„ฐ์˜ ์ด๋ฆ„์ธ ๊ฒƒ์ด๋‹ค. ๋‹จ์ˆœํžˆ ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•  App ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜ ์•ˆ์—์„œ sendRequest ํ•จ์ˆ˜๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ด๋ฆ„๋งŒ ๋ฐ”๊พผ ๊ฒƒ์ด๋‹ค.
useEffect(() => {
  fetchTasks();
}, []);
  • ๊ทธ๋ ‡๊ฒŒ ๋˜๋ฉด, ๊ธฐ์กด์— HTTP ์š”์ฒญ์„ ๋‹ด๋‹นํ–ˆ๋˜ ํ•จ์ˆ˜ ์ด๋ฆ„์ธ fetchTasks()๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๊ณ , ์•„๋ž˜์˜ useEffect ํ›… ๋กœ์ง์„ ์ˆ˜์ •ํ•  ํ•„์š”๋„ ์—†์„ ๊ฒƒ์ด๋‹ค.

useEffect์˜ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ ๋ฌธ์ œ

  • ์ปค์Šคํ…€ ํ›…์œผ๋กœ HTTP ์š”์ฒญ์„ ํ•˜๋Š” ์ฃผ์š” ๋กœ์ง๋“ค์„ ์•„์›ƒ์†Œ์‹ฑํ•˜๋ฉด์„œ useEffect ํ›…์˜ ์˜์กด์„ฑ ๋ฐฐ์—ด์— ๋ฌด์–ธ๊ฐ€ ์˜ค๋ฅ˜๊ฐ€ ์žˆ์Œ์„ ๊ฒฝ๊ณ ํ•˜๋Š” ๊ฑธ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ์ด์ „์— ์‚ฌ์šฉํ•˜๋˜ fetchTasks ํ•จ์ˆ˜์—์„œ๋Š” ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š๋˜ ๊ฒƒ์ด๋‹ค. ์ด์ „์—๋Š” ์ƒํƒœ ๊ฐฑ์‹  ํ•จ์ˆ˜๋งŒ ํ˜ธ์ถœํ•˜๊ณ  ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์˜์กด์„ฑ ๋ฐฐ์—ด์„ ๊ตณ์ด ์ฃผ์ž…ํ•˜์ง€ ์•Š์•„๋„ ์ƒ๊ด€ ์—†์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ํ•˜์ง€๋งŒ fetchTasks ํ•จ์ˆ˜, ์ฆ‰ ๋‚ด๋ถ€์˜ sendRequest ํ•จ์ˆ˜๋Š” ์ปค์Šคํ…€ ํ›… ๋‚ด๋ถ€์— ์œ„์น˜ํ•ด์žˆ๊ณ , ์ด๋ฅผ ์ถ”์ถœํ•ด์„œ ์‚ฌ์šฉํ•œ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— useEffect๋Š” ์ด sendRequest ํ•จ์ˆ˜ ์•ˆ์—์„œ ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€๋ฅผ ์•Œ์ง€ ๋ชปํ•œ๋‹ค. ๋•Œ๋ฌธ์— fetchTasks ํ•จ์ˆ˜๊ฐ€ ๋ณ€ํ™”ํ•  ๋•Œ๋งˆ๋‹ค useEffect๋ฅผ ์žฌ์‹คํ–‰ํ•˜๋ ค๋ฉด fetchTasks๋ฅผ ์˜์กด์„ฑ์œผ๋กœ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค.

๐Ÿšจ ๋ฌดํ•œ๋ฃจํ”„ ๋ฐœ์ƒ

useEffect(() => {
  fetchTasks();
}, [fetchTasks]);
  • ํ•˜์ง€๋งŒ ์ด๋Š” ํ˜„์žฌ๋กœ์„œ๋Š” ํฐ ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค. ํ˜„ ์‹œ์ ์—์„œ๋Š” ๋ฌดํ•œ ๋ฃจํ”„๊ฐ€ ๋งŒ๋“ค์–ด์ง€๊ณ  ์—๋Ÿฌ ์ƒํ™ฉ์„ ๋ฐœ์ƒ์‹œํ‚ค๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Š” ์ข‹์€ ์†”๋ฃจ์…˜์ด ๋  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ ๋‚˜์ค‘์— ๋‹ค์‹œ ๋…ผ์˜ํ•˜๊ธฐ๋กœ ํ•˜๊ณ , ๋‹ค์‹œ ์˜์กด์„ฑ์„ ์ œ๊ฑฐํ•œ๋‹ค.
useEffect(() => {
  fetchTasks();
}, []);

์ •๋ฆฌ

  • ์ง€๊ธˆ๊นŒ์ง€ ์ปค์Šคํ…€ ํ›…์„ ํ†ตํ•ด์„œ App ์ปดํฌ๋„ŒํŠธ๋ฅผ ์žฌ๊ตฌ์ถ•ํ–ˆ๋‹ค. ์ด์ œ isLoading๊ณผ error ์ƒํƒœ์— ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๊ณ , ์ด๊ฒƒ๋“ค์€ Tasks ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์— ์žˆ๋Š” ์ž์‹ ์ปดํฌ๋„ŒํŠธ์ธ Task ์ปดํฌ๋„ŒํŠธ์— ์ „๋‹ฌ๋œ๋‹ค. fetchTasks ํ•จ์ˆ˜์—๋„ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์š”์ฒญ์„ ๋ณด๋‚ด๊ฑฐ๋‚˜ ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ถ€๋ถ„์€ ์ปค์Šคํ…€ ํ›…์˜ ์ผ๋ถ€๊ฐ€ ๋˜์—ˆ๋‹ค.

  • ์ €์žฅํ•˜๊ณ , ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•ด์˜ค๋ฉด ํ˜„์žฌ ์ž‘์—…์„ ๋ชจ๋‘ ๋ถˆ๋Ÿฌ์˜ค๋ฉฐ ์ž‘์—…์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ธฐ๋Šฅ๋„ ๋™์ผํ•˜๊ฒŒ ์ž‘๋™ํ•˜๋Š” ๊ฑธ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

โœฆ ์ถœ์ฒ˜


๐Ÿšจ ํ•ด๋‹น ํฌ์ŠคํŒ…์€ Udemy์˜ โŒœReact ์™„๋ฒฝ ๊ฐ€์ด๋“œโŒŸ ๊ฐ•์˜๋ฅผ ๋ฒ ์ด์Šค๋กœ ํ•œ ๊ธฐ๋ก์ž…๋‹ˆ๋‹ค.
โœ๐Ÿป ๊ฐ•์˜ git repo ๋ฐ”๋กœ๊ฐ€๊ธฐ

profile
์ผ๋‹จ ๊ณต๋ถ€๊ฐ€ '์ ์„ฑ'์— ๋งž๋Š” ๊ฐœ๋ฐœ์ž. ๊ทผ์„ฑ์žˆ์Šต๋‹ˆ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€