React 정신무장! #26

CoderS·2022년 1월 7일
0

리액트 Remind

목록 보기
26/32

#26 달라진 나 ~

react-async 로 요청 상태 관리하기

이번에는 react-async 라는 것을 배울건데 지난번에 만들었던 useAsync 와 비슷한 함수가 들어있는 라이브러리이다.

이 라이브러리 안에 들어있는 함수 이름도 useAsync 인데, 약간 사용법이 다르다.

매번 프로젝트마다 요청 상태 관리를 위한 커스텀 Hook 을 만들기 귀찮다면, react-async 라이브러리를 사용하면 된다.

우리가 만든 커스텀 Hook 은 결과물을 배열로 반환하는 반면 이 react-async 은 객체 형태로 반환한다.

그러면 우리 프로젝트에 해당 라이브러리를 설치해준다.

$ npm install react-async

한 번 react-async 의 README 에 있는 공식 사용법을 확인해보자!

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
}

react-async 에서 useAsync 를 사용할 때 파라미터로 넣는 옵션 객체에는 호출 할 함수 promiseFn 을 넣고, 파라미터도 필드 이름과 함께 (customerId) 넣어주어야 한다.

※ User 컴포넌트 전환

그럼 이제 User 컴포넌트에서 만든 커스텀 Hook 대신 react-async 의 useAsync 로 교체해준다.

User.js

import React from 'react';
import axios from 'axios';
import { useAsync } from 'react-async';

async function getUser({ id }) {
  const response = await axios.get(
    `https://jsonplaceholder.typicode.com/users/${id}`
  );
  return response.data;
}

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

  if (isLoading) return <div>로딩중..</div>;
  if (error) return <div>에러가 발생했습니다</div>;
  if (!user) return null;

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

export default User;

우리는 useAsync 를 사용할 때에는 프로미스를 반환하는 함수의 파라미터를 객체형태로 해주어야 한다.

async function getUser({ id }) {}

위에처럼 해야 id 값을 따로 받아와서 사용 할 수 있게 된다.

그리고, useAsync 를 사용 할 때 watch 값에 특정 값을 넣어주면 이 값이 바뀔 때마다 promiseFn 에 넣은 함수를 다시 호출한다.

※ Users 컴포넌트 전환

이번에는 Users 컴포넌트를 react-async 의 useAsync 를 사용해서 전환해준다.

Users.js

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

async function getUsers() {
  const response = await axios.get(
    'https://jsonplaceholder.typicode.com/users'
  );
  return response.data;
}

function Users() {
  const [userId, setUserId] = useState(null);
  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';

async function getUsers() {
  const response = await axios.get(
    'https://jsonplaceholder.typicode.com/users'
  );
  return response.data;
}

function Users() {
  const [userId, setUserId] = useState(null);
  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;

화면을 확인해보면 이젠 렌더링 시에는 데이터 요청을 하지 않고, 불러오기 버튼을 눌렀을때 데이터 요청을 하게 된다.

※ 정리하면...

react-async 라이브러리는 정말 쓸만하고, 편리하다.
다만, 우리가 이전에 직접 만들었던 useAsync 와는 크게 다를 건 없다.

만약 우리가 직접 만들었던 useAsync 의 작동 방식을 완벽히 이해했다면 필요에 따라 커스터마이징을 해가면서 사용할 수 있어서 직접 만드는 것을 추천한다. 특히 연습용 프로젝트가 아니라, 오랫동안 유지보수 할 수도 있게 되는 프로젝트라면 더더욱 추천한다.

반면에, 작은 프로젝트이거나, 직접 만든 useAsync 의 작동 방식이 조금 어렵게 느껴지신다면 라이브러리로 설치해서 사용하는 것이 좋다.

참고 : 벨로퍼트와 함께하는 모던 리액트

느낀점 :

  • 오늘은 react-async 라는 라이브러리를 사용해서 요청 상태 관리를 해보았다.
  • 확실히 우리가 전에 만든 커스텀 Hook 보다 편리하지만, 리액트를 더 공부하기 위해서는 스스로 만들어보고 사용하는게 맞는 것 같다.
profile
하루를 의미있게 살자!

0개의 댓글