7. Mutaion を用いてデータを更新する
useMutation hook を使ってデータを更新する
Time to accomplish: 12 Minutes
Apollo client を用いた graph API データの更新は、関数を実行するのと同じくらいシンプルにおこなえます。また Apollo Client のキャッシュ機能は非常に優秀で、大抵の場合は更新された値を自動的に追従します。このセクションでは useMutation を用いたユーザーにログインをさせる機能を実装していきます。
With Apollo Client, updating data from a graph API is as simple as calling a function. Additionally, the Apollo Client cache is smart enough to automatically update in most cases. In this section, we'll learn how to use the
useMutationhook to login a user.
What is the useMutation hook?
useMutation は Apollo アプリケーションを構築する重要な要素の一つです。これはReact の Hooks API に則って作られており、GraphQL mutation を実行する関数を取得することができます。さらに、ロードしているかどうか、完了したかどうか、エラーが発生したかどうか、といった値を取得することもできます。
The
useMutationhook is another important building block in an Apollo app. It leverages React's Hooks API to provide a function to execute a GraphQL mutation. Additionally, it tracks the loading, completion, and error state of that mutation.
useMutation を使ってデータを更新するやり方は、useQuery を使って値をフェッチするやり方とほとんど同じです。大きな違いは useMutation の返り値は tuple であり、その最初の要素が mutate function である点です。この関数を実行することで mutation を実行できます。tuple の二番目の要素には「結果」オブジェクトが返ってきます。この「結果」オブジェクトには、loading と error の状態、それから mutation で返ってくる value が含まれています。では例をみてみましょう。
Updating data with a
useMutationhook from@apollo/react-hooksis very similar to fetching data with auseQueryhook. The main difference is that the first value in theuseMutationresult tuple is a mutate function that actually triggers the mutation when it is called. The second value in the result tuple is a result object that contains loading and error state, as well as the return value from the mutation. Let's see an example:
Update data with useMutation
最初のステップは GraphQL mutation を定義することです。src/pages/login.js に移動して以下のコードを複写し、ログイン画面を作っていきましょう。
The first step is defining our GraphQL mutation. To start, navigate to
src/pages/login.jsand copy the code below so we can start building out the login screen:
src/pages/login.js
import React from 'react';
import { useApolloClient, useMutation } from '@apollo/react-hooks';
import gql from 'graphql-tag';
import { LoginForm, Loading } from '../components';
const LOGIN_USER = gql`
mutation login($email: String!) {
login(email: $email)
}
`;以前と同じように gql 関数で GraphQL mutation を囲み、AST へとパースします。また次のセクションで使うことになるコンポーネントもいくつかインポートしています。では次にこの mutation を useMutation hook に渡すことで、コンポーネントに紐付けましょう。
Just like before, we're using the
gqlfunction to wrap our GraphQL mutation so it can be parsed into an AST. We're also importing some components that we'll use in the next steps. Now, let's bind this mutation to our component by passing it to theuseMutationhook:
src/pages/login.js
export default function Login() {
const [login, { data }] = useMutation(LOGIN_USER);
return <LoginForm login={login} />;
}こうすることで useMutation は mutate function (login) を返します。それからここでは data オブジェクトを、tuple の二番目の要素から分解して取得しています。最後に取得した mutate function を LoginForm コンポーネントに渡しています。
Our
useMutationhook returns a mutate function (login) and the data object returned from the mutation that we destructure from the tuple. Finally, we pass our login function to theLoginFormcomponent.
セッションが切れてもログイン状態を保持するためにログイントークンを localStorage に保存することにしましょう。(訳注:多分セキュリティ的にはこれはやらないほうがいいはず。)ではそれを実装していきます。
To create a better experience for our users, we want to persist the login between sessions. In order to do that, we need to save our login token to
localStorage. Let's learn how we can use theonCompletedhandler ofuseMutationto persist our login:
Expose Apollo Client with useApolloClient
React Apollo の主要な機能の一つに、ApolloClient instance を React の context へと注入する機能があります。useApolloClient を使って ApolloClient にアクセスし、@apollo/react-hooks コンポーネントでは提供されていないメソッドを直に実行することが可能です。
One of the main functions of React Apollo is that it puts your
ApolloClientinstance on React's context. Sometimes, we need to access theApolloClientinstance to directly call a method that isn't exposed by the@apollo/react-hookshelper components. TheuseApolloClienthook can help us access the client.
では useApolloClient を実行して client instance を取得しましょう。そして onCompleted コールバックを useMutation に渡します。ここで渡したコールバックは mutation が完了した場合に、その返り値を用いて一度だけ実行されます。このコールバック内では login token を localStorage に保存します。
Let's call
useApolloClientto get the currently configured client instance. Next, we want to pass anonCompletedcallback touseMutationthat will be called once the mutation is complete with its return value. This callback is where we will save the login token tolocalStorage.
この onCompleted ハンドラーの中で client.writeData も実行しています。これは Apollo cache が管理するローカルデータへ更新を加えるメソッドです。このローカルステイトを 直に書き換える手法 は次のセクションでより探求してきます。
In our
onCompletedhandler, we also callclient.writeDatato write local data to the Apollo cache indicating that the user is logged in. This is an example of a direct write that we'll explore further in the next section on local state management.
src/pages/login.js
export default function Login() {
const client = useApolloClient(); const [login, { loading, error }] = useMutation(
LOGIN_USER,
{
onCompleted({ login }) { localStorage.setItem('token', login); client.writeData({ data: { isLoggedIn: true } }); } }
);
if (loading) return <Loading />;
if (error) return <p>An error occurred</p>;
return <LoginForm login={login} />;
}Attach authorization headers to the request
さてほとんどログイン機能の実装が完了しました。最後に token を GraphQL request のheaders に乗せるようにしましょう。このトークンがサーバーに渡り、認証のために使われます。src/index.js に移動して ApolloClient を変更します。
We're almost done completing our login feature! Before we do, we need to attach our token to the GraphQL request's headers so our server can authorize the user. To do this, navigate to
src/index.jswhere we create ourApolloClientand replace the code below for the constructor:
src/index.js
const client = new ApolloClient({
cache,
link: new HttpLink({
uri: 'http://localhost:4000/graphql',
headers: { authorization: localStorage.getItem('token'), },
}),
});
cache.writeData({
data: {
isLoggedIn: !!localStorage.getItem('token'),
cartItems: [],
},
});HttpLink の headers option で設定を行います。GraphQL operation が作成されるたびに localStorage からトークンを取得し、リクエストの headers に与えるようにします。
Specifying the
headersoption onHttpLinkallows us to read the token fromlocalStorageand attach it to the request's headers each time a GraphQL operation is made.
では次のセクションでは Apollo を用いたローカルステイトの管理について学習します。️
In the next section, we'll add the
<Login>form to the user interface. For that, we need to learn how Apollo allows us to manage local state in our app.