๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Lect & Tip/node, Angular, React

[React] REST API, AXIOS๋กœ ๋ฐ›์•„์˜จ Array ๊ฐ์ฒด๋ฅผ mapํ•จ์ˆ˜ ํ˜ธ์ถœ์ด ๋ถˆ๊ฐ€๋Šฅํ• ๋•Œ

by st๊ณต๊ฐ„ 2024. 10. 18.

๋ชฉ์ฐจ

    [React] REST API, AXIOS๋กœ ๋ฐ›์•„์˜จ Array ๊ฐ์ฒด๋ฅผ mapํ•จ์ˆ˜ ํ˜ธ์ถœ์ด ๋ถˆ๊ฐ€๋Šฅํ• ๋•Œ

    ์ด ๊ธ€์—์„œ๋Š” React๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ REST API๋กœ๋ถ€ํ„ฐ Axios๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ฌ ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ๋ฐฐ์—ด(Array) ๊ฐ์ฒด์˜ map ํ•จ์ˆ˜ ํ˜ธ์ถœ ์˜ค๋ฅ˜์— ๋Œ€ํ•ด ์ƒ์„ธํžˆ ์„ค๋ช…ํ•˜๊ณ , ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฐ„๋‹จํ•˜๋ฉด์„œ๋„ ํšจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ•์„ ์†Œ๊ฐœํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ์™€ ๊ด€๋ จํ•˜์—ฌ Promise ๊ฐ์ฒด๊ฐ€ ํ•ด๊ฒฐ๋˜๊ธฐ ์ „์— ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋˜์–ด ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜์˜ ์›์ธ๊ณผ ํ•ด๊ฒฐ์ฑ…์„ ์ค‘์ ์ ์œผ๋กœ ๋‹ค๋ฃจ๋ฉฐ, ๋กœ๋”ฉ ์ƒํƒœ ๊ด€๋ฆฌ ๋ฐ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ํ™œ์šฉํ•œ ์ ‘๊ทผ๋ฒ•์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•ฉ๋‹ˆ๋‹ค.


    ๋„์ž…๋ถ€

    React๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์™€ ๋ Œ๋”๋งํ•˜๋Š” ๊ณผ์ •์€ ๋งค์šฐ ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค. ๋งŽ์€ ๊ฐœ๋ฐœ์ž๋“ค์ด Axios๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ REST API์™€ ํ†ต์‹ ํ•˜๋ฉฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š”๋ฐ, ์ด ๋•Œ ์ข…์ข… ๊ฒช๊ฒŒ ๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐ”๋กœ "map ํ•จ์ˆ˜ ํ˜ธ์ถœ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค"๋Š” ์—๋Ÿฌ์ž…๋‹ˆ๋‹ค.
    ์˜ˆ๋ฅผ ๋“ค์–ด, ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐฐ์—ด์ด์–ด์•ผ ํ•˜๋Š”๋ฐ, ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ํ•ด๋‹น ๋ฐฐ์—ด์— ๋Œ€ํ•ด map ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์•„์ง ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์ค‘์ผ ๋•Œ ํ•ด๋‹น ๋ณ€์ˆ˜์˜ ๊ฐ’์ด null ๋˜๋Š” Promise ๊ฐ์ฒด๋กœ ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

    ์ œ๊ฐ€ ์ฒ˜์Œ ์ด ๋ฌธ์ œ์— ์ง๋ฉดํ–ˆ์„ ๋•Œ, formdata๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ €์žฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ์ง€๋งŒ, div ์•ˆ์—์„œ ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ๊บผ๋‚ด ์“ฐ๋ ค๋‹ˆ map ํ•จ์ˆ˜ ํ˜ธ์ถœ ์‹œ “Cannot read property 'map' of null” ํ˜น์€ “map is not a function”๊ณผ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์•„์ง ์™„์ „ํžˆ ๋กœ๋“œ๋˜๊ธฐ ์ „์— ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋˜์–ด ๋ฐ์ดํ„ฐ ํƒ€์ž…์ด ์˜ˆ์ƒ๊ณผ ๋‹ค๋ฅด๊ฒŒ ๋‚˜ํƒ€๋‚˜๋Š” ๋ฌธ์ œ์˜€์Šต๋‹ˆ๋‹ค.

    ์‹ค์ œ๋กœ, API ํ˜ธ์ถœ์„ ์œ„ํ•œ Axios ์š”์ฒญ์€ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ด๋ฃจ์–ด์ง€๋ฉฐ, ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ˜ํ™˜๋˜๊ธฐ ์ „์— ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋•Œ, ๋งŒ์•ฝ ๋ฐ์ดํ„ฐ๊ฐ€ null์ด๊ฑฐ๋‚˜ ์•„์ง Promise ๊ฐ์ฒด๋กœ ๋‚จ์•„์žˆ๋‹ค๋ฉด, JavaScript์—์„œ ์ œ๊ณตํ•˜๋Š” Array.prototype.map ํ•จ์ˆ˜๋Š” ํ˜ธ์ถœ์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ์ƒํƒœ๊ฐ€ ๋˜์–ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

    ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ, ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ €๋Š” ์ด์— ๋Œ€ํ•ด ๊ฐ„๋‹จํ•œ ํ•ด๊ฒฐ์ฑ…์„ ์ƒ๊ฐํ•ด๋ƒˆ์Šต๋‹ˆ๋‹ค. ๋ฐ”๋กœ, ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์— ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” state ๋ณ€์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜๊ณ , API ํ˜ธ์ถœ์ด ์™„๋ฃŒ๋˜๋ฉด ํ•ด๋‹น state๋ฅผ ์—…๋ฐ์ดํŠธํ•˜์—ฌ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.


    ๋ฌธ์ œ ์ƒํ™ฉ๊ณผ ์›์ธ ๋ถ„์„

    React์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ๊ณผ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค:

    1. ์ปดํฌ๋„ŒํŠธ ๋งˆ์šดํŠธ ์‹œ ๋ฐ์ดํ„ฐ ์š”์ฒญ
      ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ๋  ๋•Œ, useEffect ํ›…์„ ์‚ฌ์šฉํ•˜์—ฌ Axios๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค. ์ด ๋•Œ, Axios๋Š” Promise ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
    2. ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ
      ๋น„๋™๊ธฐ ํ•จ์ˆ˜(async/await)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋ฉด, ๋ฐ์ดํ„ฐ๊ฐ€ ์™„์ „ํžˆ ๋ฐ›์•„์ง€๊ธฐ ์ „๊นŒ์ง€๋Š” ํ•ด๋‹น ๋ณ€์ˆ˜์— ์ดˆ๊ธฐ๊ฐ’(null ๋˜๋Š” ๋นˆ ๋ฐฐ์—ด ๋“ฑ)์ด ํ• ๋‹น๋ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์ดˆ๊ธฐ๊ฐ’์ด null์ด๋ผ๋ฉด, map ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
    3. ๋ Œ๋”๋ง ์‹œ์  ๋ฌธ์ œ
      ๋ฐ์ดํ„ฐ๊ฐ€ ์™„์ „ํžˆ ๋กœ๋“œ๋˜๊ธฐ ์ „์— ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋˜์–ด, ์•„์ง ๊ฐ’์ด ํ• ๋‹น๋˜์ง€ ์•Š์€ ์ƒํƒœ์˜ ๋ณ€์ˆ˜์— ๋Œ€ํ•ด map ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ˆœ๊ฐ„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

    ์˜ˆ์‹œ ์ฝ”๋“œ ๋ถ„์„

    ์•„๋ž˜๋Š” ๋ฌธ์ œ ์ƒํ™ฉ์„ ์žฌํ˜„ํ•œ ๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค:

    import React, { useState, useEffect } from 'react';
    import axios from 'axios';
    
    function DataList() {
      const [data, setData] = useState(null);
    
      useEffect(() => {
        async function fetchData() {
          try {
            const response = await axios.get('https://api.example.com/data');
            setData(response.data); // response.data๊ฐ€ ๋ฐฐ์—ด์ด๋ผ๊ณ  ๊ฐ€์ •
          } catch (error) {
            console.error('๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:', error);
          }
        }
        fetchData();
      }, []);
    
      return (
        <div>
          {/* data๊ฐ€ null์ธ ๊ฒฝ์šฐ map ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์—๋Ÿฌ ๋ฐœ์ƒ */}
          {data.map(item => (
            <div key={item.id}>{item.name}</div>
          ))}
        </div>
      );
    }
    
    export default DataList;

    ์œ„ ์ฝ”๋“œ์—์„œ๋Š” ์ดˆ๊ธฐ ์ƒํƒœ๋กœ data๋ฅผ null๋กœ ์„ค์ •ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ฒ˜์Œ ๋ Œ๋”๋ง๋  ๋•Œ data.map()์„ ํ˜ธ์ถœํ•˜๋ ค๊ณ  ํ•˜๋ฉด “Cannot read property 'map' of null” ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์™„์ „ํžˆ ๋กœ๋“œ๋˜๊ธฐ ์ „๊นŒ์ง€ ์ ์ ˆํ•œ ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.


    ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•: ๋กœ๋”ฉ ์ƒํƒœ ๊ด€๋ฆฌ์™€ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง

    ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฐ€์žฅ ์ง๊ด€์ ์ธ ๋ฐฉ๋ฒ•์€ ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ณ„๋„์˜ state ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๊ฐ€ ์™„์ „ํžˆ ๋กœ๋“œ๋œ ์ดํ›„์—๋งŒ map ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ๋กœ๋”ฉ ์ƒํƒœ ๋ณ€์ˆ˜ ์ถ”๊ฐ€

    ๋จผ์ €, ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” showList๋ผ๋Š” state ๋ณ€์ˆ˜๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ดˆ๊ธฐ๊ฐ’์€ false๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

    import React, { useState, useEffect } from 'react';
    import axios from 'axios';
    
    function DataList() {
      const [data, setData] = useState([]);
      const [showList, setShowList] = useState(false);
    
      useEffect(() => {
        async function fetchData() {
          try {
            const response = await axios.get('https://api.example.com/data');
            setData(response.data); // response.data๊ฐ€ ๋ฐฐ์—ด์ด์–ด์•ผ ํ•จ
            setShowList(true); // ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ์ด ์™„๋ฃŒ๋˜์—ˆ์Œ์„ ๋‚˜ํƒ€๋ƒ„
          } catch (error) {
            console.error('๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:', error);
          }
        }
        fetchData();
      }, []);
    
      return (
        <div>
          {/* ๋กœ๋”ฉ ์ƒํƒœ์— ๋”ฐ๋ผ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง */}
          {showList ? (
            data.map(item => (
              <div key={item.id}>{item.name}</div>
            ))
          ) : (
            <div>๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค...</div>
          )}
        </div>
      );
    }
    
    export default DataList;

    ์ด ์ฝ”๋“œ์—์„œ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๋ฐ›์•„์ง€๋ฉด setShowList(true)๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. HTML ๋ถ€๋ถ„์—์„œ๋Š” ์‚ผํ•ญ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ, showList๊ฐ€ true์ผ ๋•Œ๋งŒ ๋ฐฐ์—ด ๋ฐ์ดํ„ฐ์˜ map ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ์—๋Š” “๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค...”๋ผ๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค.

    ๊ฐœ์„  ์‚ฌํ•ญ ๋ฐ ์ถ”๊ฐ€ ๊ณ ๋ ค์‚ฌํ•ญ

    1. ์ดˆ๊ธฐ๊ฐ’ ์„ค์ •
      ๋ฐฐ์—ด ๋ฐ์ดํ„ฐ์˜ ์ดˆ๊ธฐ๊ฐ’์„ null ๋Œ€์‹  ๋นˆ ๋ฐฐ์—ด([])๋กœ ์„ค์ •ํ•˜๋ฉด, ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง ์—†์ด๋„ ๊ธฐ๋ณธ์ ์œผ๋กœ map ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด ๊ฒฝ์šฐ์—๋„ ๋ฐ์ดํ„ฐ๊ฐ€ ๋น„์–ด ์žˆ์„ ๋•Œ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ๋ช…ํ™•ํžˆ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.
    2. ์—๋Ÿฌ ํ•ธ๋“ค๋ง
      API ํ˜ธ์ถœ์ด ์‹คํŒจํ–ˆ์„ ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•˜์—ฌ ์—๋Ÿฌ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” state ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž์—๊ฒŒ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    3. ๋กœ๋”ฉ ์ปดํฌ๋„ŒํŠธ ํ™œ์šฉ
      ๋‹จ์ˆœํ•œ ํ…์ŠคํŠธ ๋Œ€์‹  ์Šคํ”ผ๋„ˆ(spinner)๋‚˜ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ณ„๋„์˜ ๋กœ๋”ฉ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค์–ด ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋งํ•˜๋ฉด ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ์•„๋ž˜๋Š” ๊ฐœ์„ ๋œ ์˜ˆ์‹œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค:

    import React, { useState, useEffect } from 'react';
    import axios from 'axios';
    import Spinner from './Spinner'; // ๋กœ๋”ฉ ์ปดํฌ๋„ŒํŠธ ์˜ˆ์‹œ
    
    function DataList() {
      const [data, setData] = useState([]);
      const [loading, setLoading] = useState(true);
      const [error, setError] = useState(null);
    
      useEffect(() => {
        async function fetchData() {
          try {
            const response = await axios.get('https://api.example.com/data');
            setData(response.data); // response.data๋Š” ๋ฐฐ์—ด์ด์–ด์•ผ ํ•จ
          } catch (error) {
            setError(error);
            console.error('๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:', error);
          } finally {
            setLoading(false); // API ํ˜ธ์ถœ์ด ๋๋‚˜๋ฉด ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ false๋กœ ๋ณ€๊ฒฝ
          }
        }
        fetchData();
      }, []);
    
      if (loading) {
        return <Spinner />; // ๋กœ๋”ฉ ์ค‘์ธ ๊ฒฝ์šฐ ์Šคํ”ผ๋„ˆ๋ฅผ ๋ Œ๋”๋ง
      }
    
      if (error) {
        return <div>๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š”๋ฐ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ๋„ํ•ด ์ฃผ์„ธ์š”.</div>;
      }
    
      return (
        <div>
          {data.map(item => (
            <div key={item.id}>{item.name}</div>
          ))}
        </div>
      );
    }
    
    export default DataList;

    ์ด์™€ ๊ฐ™์ด ๋กœ๋”ฉ, ์—๋Ÿฌ, ๋ฐ์ดํ„ฐ ์ƒํƒœ๋ฅผ ์„ธ๋ถ„ํ™”ํ•˜์—ฌ ๊ด€๋ฆฌํ•˜๋ฉด, ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ์™€ ๋ Œ๋”๋ง ๊ฐ„์˜ ํƒ€์ด๋ฐ ๋ฌธ์ œ๋กœ ์ธํ•œ ์˜ค๋ฅ˜๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


    ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์™€ Promise ๊ฐ์ฒด ์ดํ•ดํ•˜๊ธฐ

    React์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ฌ ๋•Œ ํ”ํžˆ ๊ฒช๋Š” ๋ฌธ์ œ๋Š” ๋ฐ”๋กœ Promise ๊ฐ์ฒด์™€ ๊ด€๋ จ๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. Axios์™€ ๊ฐ™์€ HTTP ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” API ํ˜ธ์ถœ ์‹œ Promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. Promise๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์˜ ์™„๋ฃŒ๋‚˜ ์‹คํŒจ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฐ์ฒด๋กœ, ๋ฐ์ดํ„ฐ๊ฐ€ ์™„์ „ํžˆ ๋„์ฐฉํ•˜๊ธฐ ์ „์— ํ•ด๋‹น ๊ฐ์ฒด๊ฐ€ ์กด์žฌํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

    Promise ๊ฐ์ฒด์˜ ํŠน์ง•

    • ๋Œ€๊ธฐ ์ƒํƒœ(Pending)
      Promise๊ฐ€ ์ƒ์„ฑ๋œ ์งํ›„์—๋Š” ์•„์ง ๊ฐ’์ด ๊ฒฐ์ •๋˜์ง€ ์•Š์€ ์ƒํƒœ์ž…๋‹ˆ๋‹ค. ์ด ๋•Œ๋Š” null ํ˜น์€ undefined์™€ ์œ ์‚ฌํ•œ ์ƒํƒœ๋กœ ๊ฐ„์ฃผํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ค€๋น„๊ฐ€ ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    • ์ดํ–‰ ์ƒํƒœ(Fulfilled)
      API ํ˜ธ์ถœ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋˜๋ฉด, Promise๋Š” ์ดํ–‰ ์ƒํƒœ๊ฐ€ ๋˜์–ด ์‹ค์ œ ๋ฐ์ดํ„ฐ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
    • ๊ฑฐ๋ถ€ ์ƒํƒœ(Rejected)
      API ํ˜ธ์ถœ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, Promise๋Š” ๊ฑฐ๋ถ€ ์ƒํƒœ๊ฐ€ ๋˜์–ด ์—๋Ÿฌ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

    ์ด๋Ÿฌํ•œ Promise์˜ ๋น„๋™๊ธฐ ํŠน์„ฑ ๋•Œ๋ฌธ์—, ๋ฐ์ดํ„ฐ๊ฐ€ ์™„์ „ํžˆ ๋ฐ›์•„์ง€๊ธฐ ์ „์— ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ์ดˆ๊ธฐ๊ฐ’์ด null์ด๊ฑฐ๋‚˜ ๋น„์–ด ์žˆ๋Š” ๋ฐฐ์—ด์ผ ๊ฒฝ์šฐ, map ํ•จ์ˆ˜์™€ ๊ฐ™์€ ๋ฐฐ์—ด ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊น๋‹ˆ๋‹ค.

    ๋”ฐ๋ผ์„œ, ๋ฐ์ดํ„ฐ๊ฐ€ ์™„์ „ํžˆ ์ดํ–‰๋˜์—ˆ์Œ์„ ๋ณด์žฅํ•˜๋Š” ๋กœ๋”ฉ ์ƒํƒœ ๊ด€๋ฆฌ๊ฐ€ ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค. ์œ„์—์„œ ์†Œ๊ฐœํ•œ ๋ฐฉ๋ฒ•์ฒ˜๋Ÿผ, API ํ˜ธ์ถœ์˜ ์™„๋ฃŒ ์‹œ์ ์„ ์ฒดํฌํ•˜๊ณ , ์ด์— ๋”ฐ๋ผ ๋ Œ๋”๋ง์„ ์ œ์–ดํ•˜๋Š” ๊ฒƒ์€ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์•ˆ์ •์ ์ธ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•œ ์ค‘์š”ํ•œ ํŒจํ„ด์ž…๋‹ˆ๋‹ค.


    ์ถ”๊ฐ€ ํŒ: ์˜ต์…”๋„ ์ฒด์ด๋‹(Optional Chaining) ํ™œ์šฉ

    ์ตœ๊ทผ JavaScript์—์„œ๋Š” ์˜ต์…”๋„ ์ฒด์ด๋‹(Optional Chaining) ์—ฐ์‚ฐ์ž(?.)๋ฅผ ์ง€์›ํ•จ์— ๋”ฐ๋ผ, ๋ฐ์ดํ„ฐ๊ฐ€ null ๋˜๋Š” undefined์ผ ๋•Œ ์•ˆ์ „ํ•˜๊ฒŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์ œ๊ณต๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์•„๋ž˜์™€ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

    return (
      <div>
        {data?.map(item => (
          <div key={item.id}>{item.name}</div>
        )) || <div>๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.</div>}
      </div>
    );

    ์ด ์ฝ”๋“œ๋Š” data๊ฐ€ ์กด์žฌํ•  ๋•Œ๋งŒ map ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด “๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.”๋ผ๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋งŒ, ์˜ต์…”๋„ ์ฒด์ด๋‹์€ ๋ฐ์ดํ„ฐ์˜ ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ํ‘œํ˜„ํ•ด์ฃผ์ง€๋Š” ์•Š์œผ๋ฏ€๋กœ, ์—ฌ์ „ํžˆ ๋กœ๋”ฉ ์ƒํƒœ์™€ ์—๋Ÿฌ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ณ„๋„์˜ ๋กœ์ง์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.


    ์ตœ์ข… ์ •๋ฆฌ ๋ฐ ๊ฒฐ๋ก 

    React์—์„œ Axios๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋ฉด์„œ map ํ•จ์ˆ˜ ํ˜ธ์ถœ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋Š” ์ฃผ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ์•„์ง Promise ๊ฐ์ฒด๋กœ ๋‚จ์•„์žˆ๊ฑฐ๋‚˜ ์ดˆ๊ธฐ๊ฐ’์ด null์ธ ์ƒํƒœ์—์„œ ๋ฐฐ์—ด ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ ์„ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

    1. ๋ฐ์ดํ„ฐ์˜ ์ดˆ๊ธฐ๊ฐ’ ์„ค์ •
      ๋ฐฐ์—ด ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃฐ ๋•Œ ์ดˆ๊ธฐ๊ฐ’์„ null์ด ์•„๋‹Œ ๋นˆ ๋ฐฐ์—ด([])๋กœ ์„ค์ •ํ•˜์—ฌ, ๊ธฐ๋ณธ์ ์ธ map ํ˜ธ์ถœ์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
    2. ๋กœ๋”ฉ ์ƒํƒœ ๊ด€๋ฆฌ
      ๋ณ„๋„์˜ state ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ , API ํ˜ธ์ถœ์ด ์™„๋ฃŒ๋˜์—ˆ์„ ๋•Œ๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด Promise ๊ฐ์ฒด๊ฐ€ ํ•ด๊ฒฐ๋˜๊ธฐ ์ „์— ๋ Œ๋”๋ง๋˜๋Š” ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    3. ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง ํ™œ์šฉ
      ์‚ผํ•ญ ์—ฐ์‚ฐ์ž๋‚˜ ๋…ผ๋ฆฌ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ, ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ ์ค‘, ์—๋Ÿฌ ๋ฐœ์ƒ, ๋ฐ์ดํ„ฐ ์ •์ƒ ๋กœ๋”ฉ ๋“ฑ ๊ฐ ์ƒํƒœ์— ๋งž๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๋„๋ก ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
    4. ์˜ต์…”๋„ ์ฒด์ด๋‹ ๊ณ ๋ ค
      ์˜ต์…”๋„ ์ฒด์ด๋‹์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์„ ๋•Œ ์•ˆ์ „ํ•˜๊ฒŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋กœ๋”ฉ ์ƒํƒœ์™€ ์—๋Ÿฌ ์ƒํƒœ๋Š” ๋ณ„๋„๋กœ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    ๊ฒฐ๋ก 

    React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์‹œ ๋‚˜ํƒ€๋‚˜๋Š” "map ํ•จ์ˆ˜ ํ˜ธ์ถœ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค"๋Š” ์˜ค๋ฅ˜๋Š” ๋ฐ์ดํ„ฐ์˜ ์ดˆ๊ธฐ ์ƒํƒœ์™€ Promise ๊ฐ์ฒด์˜ ํŠน์„ฑ์—์„œ ๊ธฐ์ธํ•ฉ๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งํ•ด, ๋ฐ์ดํ„ฐ๊ฐ€ ์™„์ „ํžˆ ๋กœ๋“œ๋˜์ง€ ์•Š์•˜์„ ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ์ด๋ฉฐ, ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” state ๋ณ€์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ์ ์šฉํ•˜๋Š” ๋ฐฉ์‹์ด ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค.
    ์‹ค์ œ ๊ฐœ๋ฐœ ํ˜„์žฅ์—์„œ๋Š” ๋ฐ์ดํ„ฐ์˜ ์ดํ–‰ ์ƒํƒœ๋ฅผ ๋ฉด๋ฐ€ํžˆ ํŒŒ์•…ํ•˜๊ณ , ์‚ฌ์šฉ์ž์—๊ฒŒ ์ ์ ˆํ•œ ํ”ผ๋“œ๋ฐฑ(๋กœ๋”ฉ ์Šคํ”ผ๋„ˆ, ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ๋“ฑ)์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด ์‚ฌ์šฉ์ž ๊ฒฝํ—˜(UX)์„ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ํ•ต์‹ฌ ์š”์†Œ์ž„์„ ๊ธฐ์–ตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    ์œ„์—์„œ ์ œ์‹œํ•œ ๋ฐฉ๋ฒ• ์™ธ์—๋„, ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€ ๋ณด์ˆ˜์„ฑ์„ ์œ„ํ•ด ์ปค์Šคํ…€ ํ›…(Custom Hook)์„ ๋งŒ๋“ค์–ด ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฐ์ดํ„ฐ ํŒจ์นญ ๋กœ์ง์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋‹ค์–‘ํ•œ ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ณตํ†ต๋œ ํŒจํ„ด์„ ํ™œ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ์š”์ฒญ, ๋กœ๋”ฉ, ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋กœ์ง์„ ํ•œ ๊ณณ์—์„œ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ๋งˆ์ง€๋ง‰์œผ๋กœ, ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ๋ณด๋‹ค ๋ช…ํ™•ํ•˜๊ฒŒ ์ดํ•ดํ•˜๊ณ , Promise์˜ ์ƒํƒœ ๋ณ€ํ™”์— ๋”ฐ๋ฅธ ์ ์ ˆํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ์–ผ๋งˆ๋‚˜ ์ค‘์š”ํ•œ์ง€ ๋‹ค์‹œ ํ•œ ๋ฒˆ ๊ฐ•์กฐํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. React์™€ Axios, ๊ทธ๋ฆฌ๊ณ  REST API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์ด๋Ÿฌํ•œ ์ ์„ ์œ ๋…ํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค๋ฉด, ๋น„์Šทํ•œ ์˜ค๋ฅ˜๋ฅผ ์‚ฌ์ „์— ๋ฐฉ์ง€ํ•˜๊ณ  ๋ณด๋‹ค ์•ˆ์ •์ ์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.


    ์ด์ƒ์œผ๋กœ, [React] REST API, AXIOS๋กœ ๋ฐ›์•„์˜จ Array ๊ฐ์ฒด์˜ map ํ•จ์ˆ˜ ํ˜ธ์ถœ ์˜ค๋ฅ˜์™€ ๊ทธ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ์— ์ด ๋‚ด์šฉ์ด ๋„์›€์ด ๋˜๊ธธ ๋ฐ”๋ผ๋ฉฐ, ์ถ”๊ฐ€์ ์ธ ์งˆ๋ฌธ์ด๋‚˜ ์˜๊ฒฌ์ด ์žˆ๋‹ค๋ฉด ๋Œ“๊ธ€์„ ํ†ตํ•ด ๊ณต์œ ํ•ด ์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

    Happy Coding!

    ๋ฐ˜์‘ํ˜•

    ๋Œ“๊ธ€