はじめに
最近暇な時で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>
)
}
useAxios(url|config, options)
引数
- url | config - configはaxiosのconfig objectです、なので基本的にaxiosで設定できるものであれば使えます。
- options - 手動実行とキャッシュの設定です
- manual - デフォルトは
false
です。true
に設定すればdidMountの時は自動実行しない。大体GETはfalse
でCUD(Create, Update, Delete)ではtrue
で使うはず。 - useCache ( true ) - デフォルトは
true
です。
- manual - デフォルトは
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はwww.mocky.io使わせていただきました。
試したいであれば公式の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と注釈は時間ができたら直します。