axios-hooks로 손쉽게 비동기 처리! redux에 thunk도 saga도 필요 없어?

소개



최근 여가 시간에 GraphQL을 만지고 프론트 엔드에서 Apollo-client를 처음 사용했습니다.
굉장히 사용하기 편리한 hooks가 있어(아마 GraphQL 모르고도 전해질까라고):
// Apollo公式より抜粋
import gql from 'graphql-tag';
import { useQuery } from '@apollo/react-hooks';

const GET_DOGS = gql`
  {
    dogs {
      id
      breed
    }
  }
`;

function Dogs({ onDogSelected }) {
  const { loading, error, data } = useQuery(GET_DOGS); // これです

  if (loading) return 'Loading...';
  if (error) return `Error! ${error.message}`;

  return (
    <select name="dog" onChange={onDogSelected}>
      {data.dogs.map(dog => (
        <option key={dog.id} value={dog.breed}>
          {dog.breed}
        </option>
      ))}
    </select>
  );
}

이거 굉장하지 않니?
비동기 처리를 한 줄로 끝내고 있습니다.

거기서 생각했습니다만, redux의 프로젝트로 사용할 수 있으면 좋겠다고.
…응? 기다려. 비동기 관련 axios를 사용하는 사람이 산처럼 보이고,
같은 것을 생각하는 사람 절대 있잖아! ?

조사하면 있었습니다, 엉망이었습니다, 산만큼 있었습니다(※ 거기까지는 없습니다).

했어.

axios-hooks



그런데, 이번 소개하는 것은 그 하나: axios-hooks 입니다
왜 이것을 선택했는지는 단순히 비교해 주었으면 하는 기능이 제일 갖추어져 있기 때문입니다. (나름대로)
다음 예제는 공식입니다.
import useAxios from 'axios-hooks'

function App() {
  const [{ data, loading, error }, refetch] = useAxios(
    'https://api.myjson.com/bins/820fc'
  )

  if (loading) return <p>Loading...</p>
  if (error) return <p>Error!</p>

  return (
    <div>
      <button onClick={refetch}>refetch</button>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  )
}

공식 CodeSandbox입니다.

useAxios(url|config, options)



인수


  • url | config - config는 axios의 config 객체 입니다. 그래서 기본적으로 axios로 설정할 수 있는 것이라면 사용할 수 있습니다.
  • options - 수동 실행 및 캐시 설정입니다.
  • manual - 기본값은 false입니다. true 로 설정하면 didMount일 때는 자동 실행하지 않는다. 대체로 GET는 false 로 CUD(Create, Update, Delete)에서는 true 로 사용할 것.
  • useCache ( true ) - 디폴트는 true 입니다.


  • Return object



    [{ data, loading, error, response }, execute]
  • data - axios의 response.data입니다.
  • loading - 이름 그대로 pending 안에서는 true 입니다.
  • error - axios error object
  • response - axios response object
  • execute([config[, options]]) - 수동 실행을 위한 function입니다. 인수는 기본적으로 이전의 config, options와 같습니다.

  • 더 완전한 예



    스스로 쓴 것입니다만, 주석은 영어가 되어 있습니다, 시간이 생기면 일본어로 고치고 싶습니다.
    테스트용 API는 ㅋㅋㅋ 심지어 cky. 이오 사용해 주셨습니다.
    시도하고 싶다면 공식 CodeSandbox에 복사하면 할 수 있다고 생각합니다.
    (ReactDOM 가져오기와 아래의 render 부분은 남아 있습니다.)
    import React from 'react';
    import Axios from 'axios';
    import useAxios, {configure} from 'axios-hooks'
    
    // Define axios instance, you could use env to split up production & development
    // The useAxios provides directly by axios-hooks use the same instance
    // If you need more than one axios instance, explain later
    const axiosInstance = Axios.create({baseURL: 'https://www.mocky.io/v2'})
    configure({axios: axiosInstance})
    
    // You should define your api url somewhere in your project
    const api = {
      getMail: { url: () => '/5ed0a6ea3500005d00ff9d7b?mocky-delay=2000ms', method: 'GET'}, 
      putMail: { url: (id) => `/5ed0a49e3500009300ff9d6b/${id}`, method: 'POST'}
    }
    
    function App() {
      // The example to get some data
      // Execute once the component did mount
      const [{data = {iam: 'default data'}, loading, error}] = useAxios({
        url: api.getMail.url(),
        method: api.getMail.method, 
        data: {haha: "yes"}
      })
      // The example to CUD data
      // Pass { manual: true } into useAxios, then it won't execute when component did mount
      const [{data: updatedData}, updateData] = useAxios({method: api.putMail.method}, {manual: true})
      return (
        <div >
          {error && <div>error</div>}
          {data && <div>{`${JSON.stringify(data)} ${loading?'loading':''}`}</div>}
          {updateData && <div>{JSON.stringify(updatedData)}</div>}
          <button onClick={() => {
              // You can set the common authorization header like this way
              axiosInstance.defaults.headers.authorization='test101'
              // Example to update data
              updateData({url: api.putMail.url('myid'), data: {thedata: 'you want to put'}, headers: {'another-header': 'test202'}})
                .then((data) => {console.log(data)}) // Use it by the way you want, even with redux store
          }}>
            test
          </button>
        </div>
      );
    }
    
    // If you need more than one axios instance, set up with makeUseAxios & export it
    // const anotherInstance = Axios.create({baseURL: 'http://some.another.api.url'})
    // export const useAnotherAxios = makeUseAxios({axios: anotherInstance})
    
    export default App;
    

    끝에



    솔직히 redux-saga 를 사용한 적이 없기 때문에 제목에서 물음표를 붙이고 있습니다. 미안합니다.
    여담입니다만 공식에서는 : axios-hooks is heavily inspired by graphql-hooks 라고 기재하고 있습니다.
    같은 graphql 의 발상으로 만든 것 같아 기쁩니다.

    CodeSandbox와 주석은 시간이 지나면 다시 할 것입니다.

    좋은 웹페이지 즐겨찾기