このチャプターの目次
今回、フロントエンドのアプリケーションは出来上がっているものを使いましたが、おまけとしてフロントエンドの簡単な解説も加えてみます。
フロントエンドのデータフェッチにはurqlを使用しました。
以下の記事が日本語でわかりやすく特徴を解説してくれています。
個人的には、Mutationを行ったあとに__typename
を見て自動でキャッシュを更新してくれるのがよさそうで、今回採用してみました。
使った感想としては、思ってたとおり本当に楽で、小さめのアプリケーションならサーバーの状態管理は全部urqlにおまかせしてしまっていいかなという気持ちになりました。
例えば、Todoの追加を行うときがあります。
addTodo
の__typename
はTodo
です。
このMutationが実行されると、__typename
にTodo
をもつクエリが再実行されます。
今回のアプリケーションの例ではTodo一覧のフェッチが再実行されるといった感じです。
開発者が自身でキャッシュの管理を行う必要がなくなるので、実装はお手軽になりそうです。
また、デフォルトのヘッダーにトークンを設定したい場合は、ちょっと複雑ですがExchangeという仕組みを利用することで設定できます。
src/components/AuthorizedUrqlProvider.tsx
import { useAuth0 } from '@auth0/auth0-react';
import React from 'react';
import {
cacheExchange,
createClient,
dedupExchange,
Exchange,
fetchExchange,
Operation,
Provider,
} from 'urql';
import { fromPromise, fromValue, map, mergeMap, pipe } from 'wonka';
import { API_HOST } from '../config/constants';
const AuthorizedUrqlProvider: React.FC = ({ children }) => {
const { getAccessTokenSilently } = useAuth0();
const fetchOptionsExchange =
(fn: any): Exchange =>
({ forward }) =>
(ops$) => {
return pipe(
ops$,
mergeMap((operation: Operation) => {
const result = fn(operation.context.fetchOptions);
return pipe(
(typeof result.then === 'function'
? fromPromise(result)
: fromValue(result)) as any,
map((fetchOptions: RequestInit | (() => RequestInit)) => ({
...operation,
context: { ...operation.context, fetchOptions },
}))
);
}),
forward
);
};
const client = createClient({
url: API_HOST,
exchanges: [
dedupExchange,
cacheExchange,
fetchOptionsExchange(async (fetchOptions: any) => {
const token = await getAccessTokenSilently();
return Promise.resolve({
...fetchOptions,
headers: {
Authorization: token ? `Bearer ${token}` : '',
},
});
}),
fetchExchange,
],
});
return <Provider value={client}>{children}</Provider>;
};
export default AuthorizedUrqlProvider;
src/main.tsx
import { Auth0Provider } from '@auth0/auth0-react';
import { ChakraProvider } from '@chakra-ui/react';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import AuthorizedUrqlProvider from './components/AuthorizedUrqlProvider';
import {
AUTH0_AUDIENCE,
AUTH0_CLIENT_ID,
AUTH0_DOMAIN,
AUTH0_REDIRECT_URI,
} from './config/constants';
ReactDOM.render(
<React.StrictMode>
<Auth0Provider
domain={AUTH0_DOMAIN}
clientId={AUTH0_CLIENT_ID}
redirectUri={AUTH0_REDIRECT_URI}
audience={AUTH0_AUDIENCE}
>
<ChakraProvider>
<AuthorizedUrqlProvider>
<App />
</AuthorizedUrqlProvider>
</ChakraProvider>
</Auth0Provider>
</React.StrictMode>,
document.getElementById('root')
);
参考