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

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

TIL

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

๋ชฉ์ฐจ

  • async ์™€ await ์‚ฌ์šฉํ•˜๊ธฐ
  • ๋กœ๋”ฉ ๋ฐ ๋ฐ์ดํ„ฐ State ์ฒ˜๋ฆฌํ•˜๊ธฐ
  • HTTP ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌํ•˜๊ธฐ

โœง async ์™€ await ์‚ฌ์šฉํ•˜๊ธฐ

ํ”„๋กœ๋ฏธ์Šค๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์–ธ์–ด์˜ ๊ธฐ๋Šฅ ์ค‘์— ํ•˜๋‚˜์ด๋‹ค

  • fetch ๋Š” ํ”„๋กœ๋ฏธ์Šค ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ ์šฐ๋ฆฌ๋Š” then() ์ฒด์ธ ์ฆ‰, then() ํ˜ธ์ถœ ๋’ค์— ๋˜ ๋‹ค์‹œ then()์„ ์žฌ์ฐจ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋Ÿฐ then() ์ฒด์ธ ๋Œ€์‹  ๊ฐ„๋‹จํ•˜๊ฒŒ async์™€ await์„ ์ด์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

async/await ๋ฅผ ํ†ตํ•œ ์ฝ”๋“œ ๊ฐ„๊ฒฐํ™”

before

function fetchMoviesHandler() {
  fetch("https://swapi.dev/api/films")
    .then((res) => {
      return res.json();
    })
    .then((data) => {
      const transformedMovies = data.results.map((movieData) => {
        return {
          id: movieData.episode_id,
          title: movieData.title,
          openingText: movieData.opening_crawl,
          releaseDate: movieData.release_date,
        };
      });
      setMovies(transformedMovies);
    });
}

after

async function fetchMoviesHandler() {
  const response = await fetch("https://swapi.dev/api/films");
  const data = await response.json();

  const transformedMovies = data.results.map((movieData) => {
    return {
      id: movieData.episode_id,
      title: movieData.title,
      openingText: movieData.opening_crawl,
      releaseDate: movieData.release_date,
    };
  });
  setMovies(transformedMovies);
}
  • befor์™€ after ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ๊ธฐ์กด์˜ then() ์ฒด์ด๋‹์„ ํ†ตํ•ด ์ž‘์„ฑํ•œ ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ณด๋‹ค async/await๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๊ฐ€ ํ›จ์”ฌ ๊ฐ€๋…์„ฑ์ด ๋†’์€ ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Š” ๋‹จ์ˆœํ•œ ์ฝ”๋“œ ๋ณ€ํ™˜์— ๊ฐ€๊นŒ์šฐ๋ฉฐ, ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ๋Š” then() ์ฒด์ด๋‹์„ ์‚ฌ์šฉํ•œ ๊ฒƒ๊ณผ ๋™์ผํ•œ ์—ญํ• ์„ ํ•  ๋ฟ์ด์ง€๋งŒ, ์ฝ”๋“œ๋ฅผ ๋‹จ์ˆœํ™” ์‹œํ‚ค๊ณ  ์ง๊ด€์ ์œผ๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋ฉฐ ๊ฐ€๋…์„ฑ ์—ญ์‹œ ๋†’์•„์ง„๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค. ๊ฒ‰์œผ๋กœ ๋ณด๊ธฐ์—” ๋‹จ๊ณ„์ ์œผ๋กœ ์‹คํ–‰๋˜๋Š” ์ฆ‰, ๋™๊ธฐ์  ์ž‘์—…์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ๋Š” then() ์ฒด์ด๋‹๊ณผ ๊ฐ™์€ ๋น„๋™๊ธฐ์  ์ž‘์—…์œผ๋กœ ์ง„ํ–‰๋˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.


โœง ๋กœ๋”ฉ ๋ฐ ๋ฐ์ดํ„ฐ State ์ฒ˜๋ฆฌํ•˜๊ธฐ

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

์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ํ†ตํ•œ ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ ์ฒ˜๋ฆฌ

  • ์˜ํ™”์˜ ์ƒํƒœ(state)๋ฅผ ๊ฐ€์ ธ์˜ค๋ฉด ์˜ํ™”๊ฐ€ ์‹ค์ œ๋กœ ์กด์žฌํ•˜๋Š”์ง€๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์‚ฌ์šฉ์ž์—๊ฒŒ ์˜ํ™”์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๊ธฐ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์ค‘์ธ์ง€๋ฅผ ์•Œ๋ฆฌ๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋˜ ๋‹ค๋ฅธ ์ƒํƒœ(state)๊ฐ€ ํ•„์š”ํ•  ๊ฒƒ์ด๋‹ค.
const [isLoding, setIsLoding] = useState(false);
  • isLoding ์ด๋ผ๋Š” boolean ์˜ false ์ดˆ๊ธฐ๊ฐ’์„ ๊ฐ€์ง€๋Š” ์ƒํƒœ(state)๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค. ์ดˆ๊ธฐ ๊ฐ’์„ false ๋กœ ์„ค์ •ํ•œ ์ด์œ ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋กœ๋“œํ•  ๋•Œ๋‚˜ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ™”๋ฉด์— ๋ Œ๋”๋ง๋  ๋•Œ ์˜ํ™” ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ”๋กœ ๋กœ๋“œ๋˜๋Š” ๊ฑด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
async function fetchMoviesHandler() {
  setIsLoding(true);
  const response = await fetch("https://swapi.dev/api/films");
  const data = await response.json();

  const transformedMovies = data.results.map((movieData) => {
    return {
      id: movieData.episode_id,
      title: movieData.title,
      openingText: movieData.opening_crawl,
      releaseDate: movieData.release_date,
    };
  });
  setMovies(transformedMovies);
  setIsLoding(false);
}
  • ํ•˜์ง€๋งŒ ์‚ฌ์šฉ์ž๊ฐ€ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ fetchMoviesHandler ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ–ˆ์„ ๋•Œ ์˜ํ™” ๋ฐ์ดํ„ฐ๊ฐ€ ๋กœ๋“œ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๊ธฐ์— setIsLoding ์„ ํ˜ธ์ถœํ•˜๊ณ , true ๊ฐ’์œผ๋กœ ์—…๋ฐ์ดํŠธํ•ด์ค€๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์˜ํ™” ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ์„ ์‹œ์ž‘ํ•  ๋•Œ ํ•ด๋‹น isLoding ์ƒํƒœ(state) ๋ณ€ํ™”๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋˜ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ํ˜ธ์ถœํ•œ ๋’ค์—๋Š” isLoding์˜ ์ƒํƒœ๋Š” false ์—ฌ์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— setMovies()๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋„˜๊ฒจ์ค€ ๋’ค์—๋Š” ๋‹ค์‹œ isLoding์˜ ์ƒํƒœ๋ฅผ false๋กœ ์—…๋ฐ์ดํŠธ ํ•ด์ค€๋‹ค.
<section>
  <MoviesList movies={movies} />
</section>
  • ๊ทธ๋ฆฌ๊ณ  ์—ฌ๊ธฐ์—์„œ isLoding์˜ ์ƒํƒœ๋ฅผ ์ด์šฉํ•ด์„œ ๋กœ๋”ฉ ์•„์ด์ฝ˜์ด๋‚˜ ๋กœ๋”ฉ ํ…์ŠคํŠธ๋ฅผ ๋ Œ๋”๋ง ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค. ๊ฐ€๋ น ๋กœ๋”ฉ ์ค‘์ด ์•„๋‹ ๋•Œ์—๋งŒ MoviesList ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.
<section>{!isLoding && <MoviesList movies={movies} />}</section>
  • ๋ฐ˜๋Œ€๋กœ, ๋กœ๋”ฉ ์ค‘์ผ ๋•Œ์—๋Š” ๋กœ๋”ฉ ์ค‘์ž„์„ ์•Œ๋ฆฌ๋Š” ํ…์ŠคํŠธ๋ฅผ ํ‘œ์‹œํ•˜๋„๋ก ํ•œ๋‹ค.
<section>
  {!isLoding && <MoviesList movies={movies} />}
  {isLoding && <p>Loding...</p>}
</section>

  • ์ €์žฅํ•˜๊ณ  ๋‹ค์‹œ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด, ์•„์ฃผ ์ž ๊น์ด์ง€๋งŒ ์˜ํ™” ๋ฐ์ดํ„ฐ๊ฐ€ ํ‘œ์‹œ๋˜๊ธฐ ์ „๊นŒ์ง€ ์šฐ๋ฆฌ๊ฐ€ ์ง€์ •ํ•œ ๋ฌธ๊ตฌ 'Loding...'์ด ํ‘œ์‹œ ๋œ๋‹ค. ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ(state)๊ฐ€ isLoding ์ด๊ฑฐ๋‚˜ !isLoding ๋งŒ ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ๋กœ๋”ฉ์ด ์™„๋ฃŒ๋˜์—ˆ์œผ๋‚˜, ์˜ํ™”์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ๋„ ๋ถ„๋ช… ์˜ˆ์™ธ์ ์œผ๋กœ ์กด์žฌํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ fetch ๋กœ ๋ฐ›์•„์˜ค๋Š” ์˜ํ™” ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์„ ๋•Œ์— ํ˜น์€ fetch ๊ฐ€ ์‹คํŒจํ•ด์„œ movies๊ฐ€ ๋นˆ ๋ฐฐ์—ด์ผ ๋•Œ๋ฅผ ๊ฐ€์ •ํ•ด์„œ ์ด๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ์•Œ๋ฆด ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
<section>
  {!isLoding && movies.length > 0 && <MoviesList movies={movies} />}
  {isLoding && <p>Loding...</p>}
</section>
  • ๋กœ๋”ฉ์ด ๋˜์ง€ ์•Š๊ณ  movies.length ๋ฅผ ์ด์šฉํ•œ ๊ฐ’์ด 0 ์ด์ƒ์ผ ๋•Œ(์ฆ‰, ๋ฐ์ดํ„ฐ๊ฐ€ 1๊ฐœ ์ด์ƒ์œผ๋กœ ๋‹ด๊ฒผ์„ ๋•Œ)๋ฅผ && ์—ฐ์‚ฐ์ž๋กœ ์ถ”๊ฐ€ํ•˜์—ฌ MoviesList ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๊ณ ,
<section>
  {!isLoding && movies.length > 0 && <MoviesList movies={movies} />}
  {!isLoding && movies.length === 0 && <p>Found no movies.</p>}
  {isLoding && <p>Loding...</p>}
</section>
  • ๋กœ๋”ฉ์ด ๋˜์ง€ ์•Š๊ณ , movies.length ๋ฅผ ์ด์šฉํ•œ ๊ฐ’์ด 0์ผ ๋•Œ(movies๊ฐ€ ๋นˆ ๋ฐฐ์—ด์ผ ๋•Œ)๋ฅผ && ์—ฐ์‚ฐ์ž๋กœ ์ถ”๊ฐ€ํ•˜์—ฌ "Found no movies." ํ…์ŠคํŠธ๋ฅผ ํ™”๋ฉด์— ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ์—ˆ๋‹ค.

  • ์ €์žฅํ•˜๊ณ  ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋‹ค์‹œ ๋ถˆ๋Ÿฌ์˜ค๋ฉด ์ดˆ๊ธฐ์—๋Š” ๋กœ๋”ฉ์ด ๋˜์ง€ ์•Š์•˜๊ณ (!isLoding), ์˜ํ™”๋„ ๋ถˆ๋Ÿฌ์˜ค์ง€ ์•Š์•˜์œผ๋‹ˆ "Found no movies." ๊ฐ€ ํ‘œ์‹œ๋˜๊ณ , ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์„œ ์˜ํ™” ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ง€์—ฐ ์‹œ๊ฐ„์—๋Š” ๋กœ๋”ฉ์ด ๋˜์—ˆ๊ธฐ์—(isLoding), "Loding..." ํ™”๋ฉด์— ํ‘œ์‹œ๋˜์—ˆ์œผ๋ฉฐ, ๋กœ๋”ฉ์ด ๋๋‚˜๊ณ (!isLoding) ์˜ํ™” ๋ฐ์ดํ„ฐ๊ฐ€ ๋‹ด๊ฒผ์œผ๋ฏ€๋กœ(movies.length > 0) ์˜ํ™” ๋ฐ์ดํ„ฐ์˜ ๋ชฉ๋ก์ด ํ™”๋ฉด์— ์ถœ๋ ฅ(MoviesList ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง)๋˜๊ณ  ์žˆ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ •๋ฆฌ

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


โœง HTTP ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌํ•˜๊ธฐ

MDN ๊ณต์‹๋ฌธ์„œ ์ฐธ๊ณ  : HTTP ์ƒํƒœ ์ฝ”๋“œ

  • HTTP ์š”์ฒญ์„ ์ „์†กํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ ๋ฌด์–ธ๊ฐ€ ์ž˜๋ชป๋œ ๊ฒƒ์ด ์žˆ๋‹ค๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ์ด ์—†๋‹ค๋˜๊ฐ€, ๋˜๋Š” ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ์ด ์™„๋ฃŒ๋˜๊ณ  ์š”์ฒญ์ด ์ „์†ก๋˜์—ˆ๋Š”๋ฐ ์˜ค๋ฅ˜ ์‘๋‹ต ์ฝ”๋“œ๋ฅผ ๋„˜๊ฒจ๋ฐ›๋Š” ๋“ฑ์˜ ๊ธฐ์ˆ ์ ์ธ ์˜ค๋ฅ˜ ๋“ฑ์„ ์ƒ๊ฐํ•ด๋ณด์ž. HTTP Status ์ฝ”๋“œ๋ฅผ ๊ณต๋ถ€ํ–ˆ๋‹ค๋ฉด ์•Œ ์ˆ˜ ์žˆ์ง€๋งŒ 404, 500, 401๊ณผ ๊ฐ™์€ ์‘๋‹ต ๋“ค์ด ๋ฐ”๋กœ ๊ทธ ์˜ค๋ฅ˜์˜ ์˜ˆ์‹œ์ผ ๊ฒƒ์ด๋‹ค.

HTTP ์ƒํƒœ ์ฝ”๋“œ

  • ๋งŒ์•ฝ 200 ์ด๋‚˜, 201 ์ฒ˜๋Ÿผ 2xx ์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” ์ฝ”๋“œ๋Š” ์ •์ƒ์ ์ธ ์‘๋‹ต์„ ๋œปํ•œ๋‹ค. ์ฆ‰ ์š”์ฒญ์ด ์ •์ƒ์ ์œผ๋กœ ์ „์†ก๋˜์—ˆ๊ณ , ์„œ๋ฒ„๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์‘๋‹ตํ–ˆ์„ ๋•Œ ๋ฐ›๋Š” ์ฝ”๋“œ๋“ค์ด๋‹ค. ํ•˜์ง€๋งŒ ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ 400 ์ด๋‚˜ 500 ๊ฐ™์€ ์‘๋‹ต ์ฝ”๋“œ๋ฅผ ๋ฐ›์„ ๊ฐ€๋Šฅ์„ฑ๋„ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ ‘๊ทผ์„ ํ—ˆ๊ฐ€๋ฐ›์ง€ ๋ชปํ•œ ์ž์›์— ๋Œ€ํ•ด ์š”์ฒญ์„ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž. ์š”์ฒญ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ „์†ก ๋˜์—ˆ๊ณ , ์‹ฌ์ง€์–ด ์ด ๊ณผ์ •์—์„œ ์•„๋ฌด๋Ÿฐ ๊ธฐ์ˆ ์ ์ธ ๋ฌธ์ œ๊ฐ€ ์—†์—ˆ์Œ์—๋„ ์„œ๋ฒ„์—์„œ 401, 403 ๊ณผ ๊ฐ™์€ ์‘๋‹ต์„ ํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด ์„œ๋ฒ„๊ฐ€ ์š”์ฒญ์„ ๋ฐ›์•˜์œผ๋‚˜ ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ์‘๋‹ต์„ ์ฃผ์ง€ ์•Š์•˜์Œ์„ ์˜๋ฏธํ•œ๋‹ค. ๊ธฐ์ˆ ์ ์œผ๋กœ๋Š” ์„ฑ๊ณต์ ์œผ๋กœ ์‘๋‹ต ๋ฐ›์€ ๊ฒƒ์ด๋‚˜ ์‘๋‹ต์— ์˜ค๋ฅ˜ ์ƒํƒœ ์ฝ”๋“œ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๊ธฐ์— ์ด๋Ÿฐ ์ฝ”๋“œ๋ฅผ ๋ฐ›๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  5xx ๋Œ€์˜ ์‘๋‹ต ์ฝ”๋“œ๋“ค์€ ์„œ๋ฒ„์— ์˜ค๋ฅ˜๊ฐ€ ์žˆ์„ ๋•Œ ๋ฐœ์ƒํ•œ๋‹ค. ์ด๊ฒƒ์ด ์›น์˜๋ฐฉ์‹์ด๋‹ค.

HTTP ์˜ค๋ฅ˜๋ฅผ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ๊นŒ?

const response = await fetch("https://swapi.dev/api/films");
  • ๋จผ์ €, ์˜ค๋ฅ˜์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ์˜ˆ์‹œ๋ฅผ ์œ„ํ•ด์„œ ์šฐ๋ฆฌ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋ฐ›์•„์™”๋˜ URL์„ ์œ ํšจํ•˜์ง€ ์•Š์€ ์ฃผ์†Œ๋กœ ์ˆ˜์ •ํ•ด๋ณด์ž.
const response = await fetch("https://swapi.dev/api/film");
  • ์ด๋ ‡๊ฒŒ ์œ ํšจํ•˜์ง€ ์•Š์€ URL ์ฃผ์†Œ๋กœ ์ˆ˜์ •์„ ํ•œ ๋’ค ์ €์žฅ์„ ํ•ด๋ณด๋ฉด, ๋ฐ์ดํ„ฐ๋Š” ๋“ค์–ด์˜ค์ง€ ์•Š๋Š”๋‹ค.

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

  • ๊ฐœ๋ฐœ์ž ๋„๊ตฌ๋ฅผ ์—ด์–ด๋ณด๋ฉด ํ•ด๋‹น ์‘๋‹ต ์˜ค๋ฅ˜ ์ฝ”๋“œ 404๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜๋„ํ–ˆ๋˜ ๋Œ€๋กœ ๊ธฐ์ˆ ์ ์œผ๋กœ๋Š” ์„ฑ๊ณต์ ์ธ ์‘๋‹ต์ด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์š”์ฒญ์ด ์„œ๋ฒ„๋กœ ๊ฐ€์„œ ์‘๋‹ต์„ ๋ฐ›์•˜์ง€๋งŒ 404 ์ฝ”๋“œ๋ฅผ ๋ฐ›์•˜๊ณ  ์ด๋Š” ๋ฌด์–ธ๊ฐ€ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Œ์„ ๋‚˜ํƒ€๋‚ธ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ๊ฒฝ์šฐ๋Š” ์„œ๋ฒ„๊ฐ€ ์ค€๋น„ํ•˜์ง€ ๋ชปํ•œ ๋ฆฌ์†Œ์Šค๋ฅผ ์š”์ฒญํ–ˆ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.

error์˜ ์ƒํƒœ(state) ์ถ”๊ฐ€ํ•˜๊ธฐ

  • ์ด๋Ÿฐ ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ถ”๊ฐ€์ ์ธ ์„ธ ๋ฒˆ์งธ ์ƒํƒœ(state)๋ฅผ ๋„์ž…ํ•ด์•ผ ํ•œ๋‹ค. ์ดˆ๊ธฐ์—๋Š” ์˜ค๋ฅ˜๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ดˆ๊ธฐ ๊ฐ’์€ null ๋กœ ์ฒ˜๋ฆฌํ•ด์ค€๋‹ค.
const [error, setError] = useState(null);
  • ๊ทธ๋ฆฌ๊ณ  fetchMoviesHandler ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด, ์ด error๋ฅผ null๋กœ ๋‹ค์‹œ ๋Œ๋ ค๋†”์•ผ ํ•œ๋‹ค. ์ด์ „์— ๋ฐ›์•˜์„ ์ˆ˜๋„ ์žˆ๋Š” ์˜ค๋ฅ˜๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด์ค˜์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
async function fetchMoviesHandler() {
  setIsLoding(true);
  setError(null);

  const response = await fetch("https://swapi.dev/api/film");
  const data = await response.json();

  const transformedMovies = data.results.map((movieData) => {
    return {
      id: movieData.episode_id,
      title: movieData.title,
      openingText: movieData.opening_crawl,
      releaseDate: movieData.release_date,
    };
  });
  setMovies(transformedMovies);
  setIsLoding(false);
}
  • ์‹ค์ œ๋กœ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ—€๋‹ค๋ฉด, ์ด๋Š” error์˜ ์ดˆ๊ธฐ ๊ฐ’ null์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— null ์ด์™ธ์˜ ๊ฐ’์„ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๊ฒƒ์ด๋‹ค.

try-catch ์‚ฌ์šฉํ•˜๊ธฐ

  • async/await ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  then() ์ฒด์ด๋‹์„ ํ†ตํ•ด ์ž‘์—…์„ ํ•œ๋‹ค๋ฉด, catch()๋ฅผ ์ด์–ด ์ถ”๊ฐ€ํ•ด์„œ ์˜ค๋ฅ˜๋ฅผ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค. ํ•˜์ง€๋งŒ async/await์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด try-catch๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. ์ฝ”๋“œ์˜ ์‹คํ–‰์„ ์‹œ๋„(try)ํ•ด์„œ ์ž ์žฌ์ ์ธ ์˜ค๋ฅ˜๋ฅผ ํฌ์ฐฉ(catch) ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋ง์ด๋‹ค.
async function fetchMoviesHandler() {
  setIsLoding(true);
  setError(null);

  try {
    const response = await fetch("https://swapi.dev/api/film");
    const data = await response.json();

    const transformedMovies = data.results.map((movieData) => {
      return {
        id: movieData.episode_id,
        title: movieData.title,
        openingText: movieData.opening_crawl,
        releaseDate: movieData.release_date,
      };
    });
    setMovies(transformedMovies);
    setIsLoding(false);
  } catch (error) {}
}
  • try ๋ธ”๋ก ์•ˆ์— ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•ด์„œ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ชจ๋“  ์ฝ”๋“œ๋“ค์„ ๋„ฃ์–ด์ฃผ๊ณ , ์ด try ๋ธ”๋ก ์•ˆ์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์ž ์žฌ์ ์ธ ์˜ค๋ฅ˜๋“ค์„ catch ๋ธ”๋ก ์•ˆ์—์„œ ํฌ์ฐฉํ•˜์—ฌ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ try ๋ธ”๋ก ์•ˆ์—์„œ ์–ด๋–ค ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค๋ฉด catch ๋ธ”๋ก์—์„œ ์ด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

fetch API ์—์„œ ์—๋Ÿฌ ์ƒํƒœ ์ฝ”๋“œ๋Š” ์—๋Ÿฌ๋กœ ์ทจ๊ธ‰๋˜์ง€ ์•Š๋Š”๋‹ค

  • ์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ๊ฐ€ ์ง๋ฉดํ•ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ ์ค‘ ํ•˜๋‚˜๋Š” fetch API ์—์„œ๋Š” ์—๋Ÿฌ ์ƒํƒœ ์ฝ”๋“œ๋ฅผ ์‹ค์ œ ์—๋Ÿฌ๋กœ ์ทจ๊ธ‰ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์‚ฌ์‹ค์ด๋‹ค. ์‹ค์ œ๋กœ ์˜ค๋ฅ˜ ์ƒํƒœ ์ฝ”๋“œ๋ฅผ ๋ฐ›๋”๋ผ๋„ ๊ธฐ์ˆ ์ ์ธ ์˜ค๋ฅ˜๋กœ์จ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค. ๋”ฐ๋ผ์„œ ์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ์ด๋ฅผ ์‹ค์ œ ์˜ค๋ฅ˜๋กœ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๊ฒŒ ๋œ๋‹ค. ๊ฐ€์ ธ์˜ค์ง€ ๋ชปํ•œ ๋ฐ์ดํ„ฐ๋กœ ์–ด๋–ค ์ž‘์—…์„ ํ•˜๋ ค๊ณ  ํ•  ๋•Œ๋งŒ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๋Š” ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์ด ์•„๋‹ˆ๋‹ค.

์—๋Ÿฌ ์ƒํƒœ ์ฝ”๋“œ๋ฅผ ๋ฐ›์•˜์„ ๋•Œ ์‹ค์ œ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•

  • fetch API ์—์„œ๋Š” ์—๋Ÿฌ ์ƒํƒœ ์ฝ”๋“œ๋ฅผ ์‹ค์ œ ์—๋Ÿฌ๋กœ ์ทจ๊ธ‰ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์šฐ๋ฆฌ๊ฐ€ ์—๋Ÿฌ๋ฅผ ๋ณด๋‹ค ์šฐ์•„ํ•œ ๋ฐฉ์‹์œผ๋กœ ์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์˜ค๋ฅ˜ ์ƒํƒœ ์ฝ”๋“œ๋ฅผ ๋ฐ›์•˜์„ ๋•Œ ์‹ค์ œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋„๋ก ํ•  ์ˆ˜๋„ ์žˆ์„ ๊ฒƒ์ด๋‹ค. ๋ฌผ๋ก  axios ๊ฐ™์€ ์„œ๋“œ ํŒŒํ‹ฐ ํŒจํ‚ค์ง€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ฐ™์€ ๊ฒฝ์šฐ ์š”์ฒญ ์ „์†ก์— ์„ฑ๊ณตํ•˜๋ฉด ์˜ค๋ฅ˜ ์ƒํƒœ ์ฝ”๋“œ์— ๋งž๋Š” ์˜ค๋ฅ˜๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ „๋‹ฌํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ํฌํ•จํ•˜๊ณ  ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ๋Š” axios๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  fetch API ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋‹ˆ ์šฐ๋ฆฌ๊ฐ€ ์ง์ ‘ ์˜ค๋ฅ˜๋ฅผ ๋งŒ๋“ค์–ด์•ผ ๋œ๋‹ค.
try {
  const response = await fetch("https://swapi.dev/api/film");
  const data = await response.json();

  if (!response.ok) {
    throw new Error("Something went wrong!");
  }

  const transformedMovies = data.results.map((movieData) => {
    return {
      id: movieData.episode_id,
      title: movieData.title,
      openingText: movieData.opening_crawl,
      releaseDate: movieData.release_date,
    };
  });
  setMovies(transformedMovies);
  setIsLoding(false);
} catch (error) {}
  • ์šฐ๋ฆฌ๊ฐ€ ์ „๋‹ฌ๋ฐ›๊ฒŒ ๋˜๋Š” response ๊ฐ์ฒด์—๋Š” ok ๋ผ๋Š” ํ•„๋“œ๊ฐ€ ์กด์žฌํ•œ๋‹ค. ์ด๋Š” ์š”์ฒญ์ด ์„ฑ๊ณต์ ์ธ์ง€ ๊ทธ๋ ‡์ง€ ์•Š์€์ง€๋ฅผ ํ‘œ์‹œํ•˜๋Š” ์˜์—ญ์ด๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ์ด ok ํ•„๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ์‘๋‹ต์ด ok ์ธ์ง€ ์•„๋‹Œ์ง€๋ฅผ ํ™•์ธํ•˜๊ณ  ์ด์— ๋Œ€ํ•ด ์ž์ฒด์ ์ธ ์˜ค๋ฅ˜๋ฅผ ๋งŒ๋“ค์–ด์„œ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์—ฌ๊ธฐ์— ์ ๋‹นํ•œ ์˜ค๋ฅ˜ ๋ฉ”์„ธ์ง€๋ฅผ new Error()๋กœ ์ƒ์„ฑํ•ด์„œ ํ‘œ์‹œํ•˜๋ฉด ๋œ๋‹ค. ๋ฌผ๋ก  ์„œ๋ฒ„์—์„œ ๋Œ์•„์˜ค๋Š” ์˜ค๋ฅ˜ ์‘๋‹ต ์ฝ”๋“œ์— ๋”ฐ๋ผ์„œ ์˜ค๋ฅ˜ ๋ฉ”์„ธ์ง€๋ฅผ ๊ฐœ๋ณ„์ ์œผ๋กœ ์ฝ์–ด๋“ค์ผ ์ˆ˜๋„ ์žˆ๊ณ , ๋‹จ์ง€ ์•ž์„œ ์šฐ๋ฆฌ๊ฐ€ ํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ๋ฉ”์„ธ์ง€๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์•„๋ฌดํŠผ ์ด ๋ฉ”์„ธ์ง€๋Š” ์‘๋‹ต(response)์— ๋ฌธ์ œ๊ฐ€ ์žˆ์„ ๋•Œ์—๋งŒ ํ‘œ์‹œํ•˜๋„๋ก ํ•  ๊ฒƒ์ด๋‹ค.

catch() ์‚ฌ์šฉํ•˜๊ธฐ

async function fetchMoviesHandler() {
  setIsLoding(true);
  setError(null);

  try {
    const response = await fetch("https://swapi.dev/api/film");
    const data = await response.json();

    if (!response.ok) {
      throw new Error("Something went wrong!");
    }
    ...

  } catch (error) {

  }
}
  • ์—ฌ๊ธฐ์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋‹น์—ฐํžˆ ๊ทธ ๋‹ค์Œ ๋‹จ๊ณ„์˜ ์ฝ”๋“œ๋Š” ์ง„ํ–‰์ด ๋˜์ง€ ์•Š์„ ํ…Œ๋‹ˆ ๋Œ€์‹ ์— catch() ๋ธ”๋ก์„ ๋งŒ๋“ค์–ด๋‘” ๊ฒƒ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  catch() ๋ธ”๋ก ์•ˆ์—์„œ setError๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  null ๊ฐ’์ด ์•„๋‹Œ ์˜ค๋ฅ˜ ๋ฉ”์„ธ์ง€๋ฅผ ๋„ฃ์–ด๋‘”๋‹ค.
catch (error) {
  setError(error.message);
}
  • ์ด์ œ error ๋Š” null ์ด ์•„๋‹Œ ๋ฌธ์ž์—ด(error.message)์ด ๋˜์—ˆ๋‹ค. ์ด์ œ error ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์œผ๋‹ˆ ํ™”๋ฉด์— ํ‘œ์‹œ๋˜๋Š” ๊ฒƒ๋“ค ์—ญ์‹œ ์ •ํ•ด์ค˜์•ผ ํ•œ๋‹ค. ์˜ค๋ฅ˜์˜ ์กด์žฌ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ํ‘œ์‹œ๋˜๋Š” ๊ฒƒ๋“ค๋„ ๋ณ€ํ™”ํ•ด์•ผ ํ•˜๊ธฐ ๋–„๋ฌธ์ด๋‹ค.

error ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ํ™”๋ฉด์— ํ‘œ์‹œ๋˜๋Š” ๊ฒƒ

{
  !isLoding && movies.length > 0 && <MoviesList movies={movies} />;
}
{
  !isLoding && movies.length === 0 && <p>Found no movies.</p>;
}
{
  isLoding && <p>Loding...</p>;
}
  • ์œ„์˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ ์กฐ๊ฑด์— ๋”ฐ๋ผ์„œ ํŠน์ • ์ปจํ…์ธ ๋ฅผ ๋ Œ๋”๋งํ•  ๊ฒƒ์ด๋‹ค. ๋จผ์ € ๋กœ๋”ฉ ์ค‘์ด ์•„๋‹Œ์ง€๋ฅผ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค. ๋กœ๋”ฉ ์ค‘์ด๋ผ๋ฉด ์ด์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ ค์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
{
  !isLoding && error && <p>{error}</p>;
}
  • ํ•˜์ง€๋งŒ ๋กœ๋”ฉ ์ค‘์ด ์•„๋‹ˆ๊ณ (!isLoding) ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋‹ค๋ฉด (error๊ฐ€ null์ด ์•„๋‹ˆ๋ผ, ๊ฐ’์ด ์กด์žฌํ•œ๋‹ค๋ฉด) ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋„๋ก ์ž‘์„ฑํ•ด์ค€๋‹ค.
async function fetchMoviesHandler() {
  setIsLoding(true);
  setError(null);

  try {
    const response = await fetch("https://swapi.dev/api/film");
    const data = await response.json();

    if (!response.ok) {
      throw new Error("Something went wrong!");
    }
    ...
    setMovies(transformedMovies);
    setIsLoding(false);

  } catch (error) {
    setError(error.message);
    setIsLoding(false);
  }
}
  • ๋˜ํ•œ, ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋˜๋ฉด ๋”์ด์ƒ ๋กœ๋”ฉ์ด ํ•„์š” ์—†๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” ๋ฐ˜๋“œ์‹œ ๋กœ๋”ฉ์„ ์ค‘๋‹จ(setIsLoding(false))๋˜๊ฒŒ ํ•ด์•ผ๋งŒ ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ๊ตฌ๋ฌธ(setIsLoding(false))์„ try-catch ๋ธ”๋ก ๋’ค์— ์„ค์ •ํ•ด์„œ ์‘๋‹ต์„ ์„ฑ๊ณต์ ์œผ๋กœ ๋ฐ›์•˜๊ฑฐ๋‚˜ ์˜ค๋ฅ˜๋ฅผ ๋ฐ›์•˜๋“  ์ƒ๊ด€์—†์ด setIsLoding(false)์„ ์„ค์ •ํ•˜์—ฌ ๋กœ๋”ฉ์ด ๋๋‚ฌ์Œ์„ ์•Œ๋ฆฌ๋Š” ๊ฒƒ๋„ ๊ดœ์ฐฎ์„ ๊ฒƒ์ด๋‹ค.
async function fetchMoviesHandler() {
  setIsLoding(true);
  setError(null);

  try {
    const response = await fetch("https://swapi.dev/api/film");
    const data = await response.json();

    if (!response.ok) {
      throw new Error("Something went wrong!");
    }
    ...
    setMovies(transformedMovies);

  } catch (error) {
    setError(error.message);
  }

  setIsLoding(false);
}
  • ์ด๋ ‡๊ฒŒ ์ž‘์„ฑ์„ ํ•˜๊ณ  ์ €์žฅํ•œ ๋’ค ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด, ๋กœ๋”ฉ์ด ๋๋‚˜๊ณ  "Found no movies." ๋ฌธ๊ตฌ์™€ ํ•จ๊ป˜ ์šฐ๋ฆฌ๊ฐ€ ์„ค์ •ํ•œ ์˜ค๋ฅ˜ ๋ฉ”์„ธ์ง€(error.message)๊ฐ€ ์ถœ๋ ฅ๋˜๊ณ  ์žˆ๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

  • "Unexpected token < in JSON at position 1" ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ฝ”๋“œ ์•ˆ์—์„œ ์„ค์ •ํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, JSON์— ๋Œ€ํ•œ ์‘๋‹ต์„ ํ˜ธ์ถœํ–ˆ์Œ์—๋„ ์šฐ๋ฆฌ๊ฐ€ ์„ค์ •ํ•œ ์—๋Ÿฌ ๋ฉ”์„ธ์ง€๋ฅผ ๋ฐ›์•„์˜ค๋Š”๋ฐ ์‹คํŒจํ•œ ๊ฒƒ์ด๋‹ค. ์œ ํšจํ•˜์ง€ ์•Š์€ API ์—”๋“œ ํฌ์ธํŠธ์— ๋Œ€ํ•ด ์š”์ฒญ์„ ํ–ˆ๊ณ , ๋”ฐ๋ผ์„œ JSON ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค์ง€ ๋ชปํ–ˆ๋Š”๋ฐ๋„ ๋ง์ด๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ, response ๋ฐ”๋”” ๋ถ€๋ถ„์„ ํŒŒ์‹ฑํ•˜๊ธฐ ์ด์ „์— response์˜ ์‘๋‹ต์ด ok ์ธ์ง€๋ฅผ ๋จผ์ € ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค.
const response = await fetch("https://swapi.dev/api/film");
if (!response.ok) {
  throw new Error("Something went wrong!");
}

const data = await response.json();
  • ์˜ค๋ฅ˜ ์‘๋‹ต์„ ๋‹ค๋ฃจ๋Š” ์ข€ ๋” ํ™•์‹คํ•œ ๋ฐฉ๋ฒ•์€ ์–ด๋–ค API์™€ ํ†ต์‹ ํ•˜๋Š”์ง€์— ๋‹ฌ๋ ค์žˆ๋‹ค. ๋ช‡ ๋ช‡ API๋Š” ์š”์ฒญ์ด ์„ฑ๊ณต์ ์ด์ง€ ๋ชปํ—€์Œ์—๋„ JSON ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ผ ๋•Œ๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” API๋Š” ์š”์ฒญ์ด ์„ฑ๊ณต์ ์ด์ง€ ๋ชปํ•˜๋ฉด JSON ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ด์— ๋งž์ถฐ์„œ ํŒŒ์‹ฑ ์ „์— ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

  • ๋‹ค์‹œ ์ €์žฅํ•˜๊ณ  ์ด์ „๊ณผ ๋™์ผํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ์‹œ๋„ํ•˜์ž, ์ด๋ฒˆ์—” ์šฐ๋ฆฌ๊ฐ€ ์„ค์ •ํ•œ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ "Something went wrong!" ๊ฐ€ ์ถœ๋ ฅ๋˜๊ณ  ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

์กฐ๊ฑด์— ๋”ฐ๋ฅธ ๋ฉ”์„ธ์ง€ ๋ฌธ๊ตฌ ์ถœ๋ ฅํ•˜๊ธฐ

{
  !isLoding && movies.length > 0 && <MoviesList movies={movies} />;
}
{
  !isLoding && movies.length === 0 && <p>Found no movies.</p>;
}
{
  !isLoding && error && <p>{error}</p>;
}
{
  isLoding && <p>Loding...</p>;
}
  • "Something went wrong!" ๊ฐ€ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์€ ์šฐ๋ฆฌ๊ฐ€ ์˜๋„ํ•œ ์ ์ด์ง€๋งŒ, "Found no movies." ๋ฉ”์„ธ์ง€ ์—ญ์‹œ ๋™์‹œ์— ์ถœ๋ ฅ๋˜๋Š” ๊ฑด ์˜๋„ํ•˜์ง€ ์•Š์•˜๋‹ค. ์ด ๋ถ€๋ถ„์˜ ์กฐ๊ฑด ์ฒ˜๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•ด์ค˜์•ผ ํ•  ํ•„์š”์„ฑ์ด ์žˆ์–ด๋ณด์ธ๋‹ค.
{
  !isLoding && movies.length > 0 && <MoviesList movies={movies} />;
}
{
  !isLoding && movies.length === 0 && !error && <p>Found no movies.</p>;
}
{
  !isLoding && error && <p>{error}</p>;
}
{
  isLoding && <p>Loding...</p>;
}
  • "Found no movies." ๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ์กฐ๊ฑด์‹์— ์—๋Ÿฌ๊ฐ€ ์•„๋‹ ๋•Œ(!error)๋ฅผ && ์—ฐ์‚ฐ์ž๋กœ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

  • ๋”์ด์ƒ "Found no movies." ๋ฌธ๊ตฌ๋Š” ์ถœ๋ ฅ๋˜์ง€ ์•Š๋Š” ๊ฑธ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

  • ์ด๊ฒƒ์ด HTTP ์š”์ฒญ ์ „์†ก์—์„œ ๊ฐ๊ฐ์˜ ์„œ๋กœ ๋‹ค๋ฅธ ์ƒํƒœ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. ์–ด๋–ค ๋ฐฑ์—”๋“œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ํ†ต์‹ ํ•˜๋“  ๊ฐ„์— ์„œ๋กœ ๋‹ค๋ฅธ ์ƒํƒœ(state)๋ฅผ ๋งˆ์ฃผํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๊ฒฝ์šฐ์— ๋”ฐ๋ฅธ ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ•์„ ์•„๋Š” ๊ฒƒ์€ ์ค‘์š”ํ•˜๋‹ค. ํ•ญ์ƒ ์‘๋‹ต(response)์„ ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ๋˜๋‹ค ๋ณด๋ฉด ์˜ค๋ฅ˜(error)๋ฅผ ๋ฐ›์„ ์ˆ˜๋„ ๋นˆ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์„ ์ˆ˜๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฌํ•œ ์—ฌ๋Ÿฌ ์‹œ๋‚˜๋ฆฌ์˜ค์— ๋Œ€์‘ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ํ•ธ๋“ค๋งํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์กฐ๊ฑด์— ๋”ฐ๋ฅธ content ์ถœ๋ ฅํ•˜๊ธฐ

{
  !isLoding && movies.length > 0 && <MoviesList movies={movies} />;
}
{
  !isLoding && movies.length === 0 && !error && <p>Found no movies.</p>;
}
{
  !isLoding && error && <p>{error}</p>;
}
{
  isLoding && <p>Loding...</p>;
}
  • ์ด์ฒ˜๋Ÿผ ์ฝ”๋“œ ์•ˆ์—์„œ ๋ชจ๋“  ์กฐ๊ฑด์„ ํ™•์ธํ•˜๋Š” ๋Œ€์‹ , ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
let content = "Found no movies.";
  • ๋จผ์ € ๋ณ€์ˆ˜ content์— ๊ธฐ๋ณธ ๊ฐ’์œผ๋กœ "Found no movies." ๋ฌธ๊ตฌ๋ฅผ ํ• ๋‹นํ•ด์ค€๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด์ œ ์šฐ๋ฆฌ๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์ƒํƒœ(state)์— ๋”ฐ๋ผ์„œ ์ด ์ƒ์ˆ˜(content)์˜ ๊ฐ’์„ ๋‹ค๋ฅด๊ฒŒ ํ• ๋‹นํ•ด๋ณด์ž.
let content = "Found no movies.";

if (isLoding) {
  content = <p>Loding...</p>;
}
  • ์˜ˆ๋ฅผ ๋“ค์–ด์„œ, ๋กœ๋”ฉ ์ค‘(isLoding) ์ด๋ผ๋ฉด, content์˜ ๊ฐ’์„ <p>Loding...</p>๋กœ ํ• ๋‹นํ•œ๋‹ค. ํ•ด๋‹น if ๋ฌธ ์ฝ”๋“œ๋Š” ์กฐ๊ฑด์— ํ•ด๋‹นํ•˜๋Š” ๋ชจ๋“  ๊ฒƒ๋“ค์„ ๋ฎ์–ด์“ธ ํ…Œ๋‹ˆ ์ด ์กฐ๊ฑด์— ๋Œ€ํ•ด์„œ๋Š” ๋งˆ์ง€๋ง‰์— ํ™•์ธํ•˜๋„๋ก ํ•˜๊ณ , ๋‹ค๋ฅธ ์กฐ๊ฑด์‹๋“ค์„ ์ถ”๊ฐ€ํ•ด๋ณด์ž.
let content = "Found no movies.";

if (error) {
  content = <p>{error}</p>;
}

if (isLoding) {
  content = <p>Loding...</p>;
}
  • ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋Š”์ง€(error) ํ™•์ธํ•ด์„œ ๋งŒ์•ฝ ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋‹ค๋ฉด(error๊ฐ€ null ์ด ์•„๋‹ ๋•Œ) <p>{error}</p>๋ฅผ content ์˜ ๊ฐ’์œผ๋กœ ํ• ๋‹นํ•œ๋‹ค.
let content = "Found no movies.";

if (movies.length > 0) {
  content = <MoviesList movies={movies} />;
}

if (error) {
  content = <p>{error}</p>;
}

if (isLoding) {
  content = <p>Loding...</p>;
}
  • ๋ฌผ๋ก , ์š”์ฒญ์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ฌ ๋•Œ๋„ ์ฒ˜๋ฆฌํ•ด์ค˜์•ผ ํ•œ๋‹ค. ์ด์ „์— ์šฐ๋ฆฌ๊ฐ€ ์กฐ๊ฑด์‹์— ์ถ”๊ฐ€ํ•ด์ฃผ์—ˆ๋˜ ๋ฐฉ์‹ ๋Œ€๋กœ if ๋ฌธ์— movies.length > 0 ์ผ ๋•Œ๋ฅผ ๊ฐ€์ •(๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด์™”์„ ๋•Œ)ํ•ด์„œ MoviesList ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋ง ํ•  ์ˆ˜ ์žˆ๋„๋ก content ์˜ ๊ฐ’์œผ๋กœ ํ• ๋‹น ํ•œ๋‹ค.
<section>{content}</section>
  • ๋งˆ์ง€๋ง‰์œผ๋กœ ๋จผ์ € ์กฐ๊ฑด์‹์œผ๋กœ ๋งŒ๋“ค์–ด ๋‘์—ˆ๋˜ JSX ์˜ ๋ชจ๋“  ์ฝ”๋“œ๋“ค์„ ์ œ๊ฑฐํ•˜๊ณ  ์•ž์„œ ์„ค์ •ํ•œ ๋ณ€์ˆ˜ content๋งŒ ๋ Œ๋”๋ง ํ•ด์ค€๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด content ๋ณ€์ˆ˜์— ์žˆ๋Š” ๊ฐ’์€ ๊ฐ๊ฐ์˜ ์ƒํƒœ(state)์— ๋”ฐ๋ผ์„œ ๋‹ค๋ฅด๊ฒŒ ํ• ๋‹น๋  ๊ฒƒ์ด๋‹ค.

โœฆ ์ถœ์ฒ˜


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

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

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