๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

React/API ์—ฐ๋™

[React] #5 | react-async, ์š”์ฒญ ์ƒํƒœ ๊ด€๋ฆฌํ•˜๊ธฐ

๐Ÿ’กreact-async?

  • #4์—์„œ ๋งŒ๋“  useAsync์™€ ๋น„์Šทํ•œ ํ•จ์ˆ˜๊ฐ€ ๋“ค์–ด์žˆ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • ์ด์•ˆ์˜ ํ•จ์ˆ˜์ด๋ฆ„๋„ useAsync : ์‚ฌ์šฉ๋ฒ•์ด ์ข€ ๋‹ค๋ฆ„!

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜

yarn add react-async

react-async์˜ ๊ณต์‹ ์‚ฌ์šฉ๋ฒ•

import { useAsync } from "react-async"

const loadCustomer = async ({ customerId }, { signal }) => {
  const res = await fetch(`/api/customers/${customerId}`, { signal })
  if (!res.ok) throw new Error(res)
  return res.json()
}

const MyComponent = () => {
  const { data, error, isLoading } = useAsync({ promiseFn: loadCustomer, customerId: 1 })
  if (isLoading) return "Loading..."
  if (error) return `Something went wrong: ${error.message}`
  if (data)
    return (
      <div>
        <strong>Loaded some data:</strong>
        <pre>{JSON.stringify(data, null, 2)}</pre>
      </div>
    )
  return null
}
  • ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„ฃ๋Š” ์˜ต์…˜ ๊ฐ์ฒด์—๋Š” ํ˜ธ์ถœํ•  ํ•จ์ˆ˜ promiseFn์„ ๋„ฃ๊ณ , ํŒŒ๋ผ๋ฏธํ„ฐ๋„ ํ•„๋“œ ์ด๋ฆ„๊ณผ ํ•จ๊ป˜ (customId)๋ฅผ ๋„ฃ์–ด์ฃผ์–ด์•ผํ•œ๋‹ค.

1๏ธโƒฃ User ์ปดํฌ๋„ŒํŠธ ์ „ํ™˜

  • react-async์˜ useAsync๋กœ ์ „ํ™˜ํ•ด๋ณด์ž

User.js

import React from 'react'
import axios from 'axios';
import useAsync from './useAsync';

async function getUser({id}){
    const response = await axios.get(
        'api์ฃผ์†Œ/${id}'
    );
    return response.data;
}

function Users({ id }) {

    const { data: user, error, isLoading } = useAsync({
        promiseFn: getUser,
        id,
        watch: id
    })


    if (isLoading) return <div>๋กœ๋”ฉ์ค‘..</div>     // ๋กœ๋”ฉ์ด ํ™œ์„ฑํ™”๋˜์—ˆ์„ ๋•Œ
    if (error) return <div>์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.</div>
    if (!users) return null;

    return (
        <div>
            <h2>{user.username}</h2>
            <p>
                <b>Email:</b> {user.email}
            </p>
        </div>
    )
}

export default Users

useAsync๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์—๋Š” ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๊ฐ์ฒดํ˜•ํƒœ๋กœ ํ•ด์ฃผ์–ด์•ผํ•œ๋‹ค.

async function getUser({ id }) {}

๊ทธ๋ž˜์•ผ, id ๊ฐ’์„ ๋”ฐ๋กœ ๋ฐ›์•„์™€์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

๊ทธ๋ฆฌ๊ณ , useAsync๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ, watch ๊ฐ’์— ํŠน์ • ๊ฐ’์„ ๋„ฃ์–ด์ฃผ๋ฉด ์ด ๊ฐ’์ด ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค promiseFn ์— ๋„ฃ์€ ํ•จ์ˆ˜๋ฅผ ๋‹ค์‹œ ํ˜ธ์ถœํ•ด ์ค€๋‹ค.

 

 

2๏ธโƒฃ Users ์ปดํฌ๋„ŒํŠธ ์ „ํ™˜

Users.js

import React, { useState } from 'react';
import axios from 'axios';
import { useAsync } from 'react-async';
import User from './User';

// useAsync ์—์„œ๋Š” Promise ์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”๋กœ data ์— ๋‹ด๊ธฐ ๋•Œ๋ฌธ์—,
// ์š”์ฒญ์„ ํ•œ ์ดํ›„ response ์—์„œ data ์ถ”์ถœํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋”ฐ๋กœ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.
async function getUsers() {
  const response = await axios.get(
    'api ์ฃผ์†Œ'
  );
  return response.data;
}

function Users() {
  const [userId, setUserId] = useState(null);   //userId ์ƒํƒœ๊ด€๋ฆฌ
  
  const { data: users, error, isLoading, reload } = useAsync({
      promiseFn: getUsers
  })
  if (isLoading) return <div>๋กœ๋”ฉ์ค‘..</div>;
  if (error) return <div>์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค</div>;
  if (!users) return <button onClick={reload}>๋ถˆ๋Ÿฌ์˜ค๊ธฐ</button>;
  return (
    <>
      <ul>
        {users.map(user => (
          <li
            key={user.id}
            onClick={() => setUserId(user.id)}
            style={{ cursor: 'pointer' }}
          >
            {user.username} ({user.name})
          </li>
        ))}
      </ul>
      <button onClick={reload}>๋‹ค์‹œ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ</button>
      {userId && <User id={userId} />}
    </>
  );
}

export default Users;
  • reload ํ•จ์ˆ˜ : ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

 

์ง€๊ธˆ์€, ์ด์ „์— Users ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค ๋•Œ, ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์•ผ๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋„๋ก ๋งŒ๋“ค์–ด์คฌ์—ˆ๋Š”๋ฐ, ์ด๋ ‡๊ฒŒ ํ•ด์ฃผ๋ฉด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ์‹œ์ ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ฒŒ ๋œ๋‹ค.

 

๋งŒ์•ฝ ์ด์ „์— ๋ฐฐ์› ๋˜ skip ์ฒ˜๋Ÿผ, ๋ Œ๋”๋ง ํ•˜๋Š” ์‹œ์ ์ด ์•„๋‹Œ ์‚ฌ์šฉ์ž์˜ ํŠน์ • ์ธํ„ฐ๋ ‰์…˜์— ๋”ฐ๋ผ API๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์‹ถ์„ ๋• promiseFn ๋Œ€์‹  deferFn ์„ ์‚ฌ์šฉํ•˜๊ณ , reload ๋Œ€์‹  run ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

Users.js

import React, { useState } from 'react';
import axios from 'axios';
import { useAsync } from 'react-async';
import User from './User';

// useAsync ์—์„œ๋Š” Promise ์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”๋กœ data ์— ๋‹ด๊ธฐ ๋•Œ๋ฌธ์—,
// ์š”์ฒญ์„ ํ•œ ์ดํ›„ response ์—์„œ data ์ถ”์ถœํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋”ฐ๋กœ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.
async function getUsers() {
  const response = await axios.get(
    'api ์ฃผ์†Œ'
  );
  return response.data;
}

function Users() {
  const [userId, setUserId] = useState(null);   //userId ์ƒํƒœ๊ด€๋ฆฌ
  
  const { data: users, error, isLoading, run } = useAsync({
      deferFn: getUsers
  })
  if (isLoading) return <div>๋กœ๋”ฉ์ค‘..</div>;
  if (error) return <div>์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค</div>;
  if (!users) return <button onClick={run}>๋ถˆ๋Ÿฌ์˜ค๊ธฐ</button>;
  return (
    <>
      <ul>
        {users.map(user => (
          <li
            key={user.id}
            onClick={() => setUserId(user.id)}
            style={{ cursor: 'pointer' }}
          >
            {user.username} ({user.name})
          </li>
        ))}
      </ul>
      <button onClick={run}>๋‹ค์‹œ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ</button>
      {userId && <User id={userId} />}
    </>
  );
}

export default Users;

์ด์ œ, ๋ Œ๋”๋ง ์‹œ์—๋Š” ๋ฐ์ดํ„ฐ ์š”์ฒญ์„ ํ•˜์ง€ ์•Š๊ณ , ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ ๋ฐ์ดํ„ฐ ์š”์ฒญ์„ ํ•˜๊ฒŒ ๋œ๋‹ค.

 

 


Reference

๋ฒจ๋กœํผํŠธ์˜ ๋ชจ๋˜ ๋ฆฌ์•กํŠธ