こんにちは、mabuiです。
最近仕事でGraphQLを使用していて、これは筋がいい技術だな〜流行ってほしいな〜〜と思っており、今後自分でもサービス作りに活用したいと考えています。
そこで今回は、GraphQLをクライアントから操作する時に便利なライブラリ、Apollo Clientを使用して、Mutationの使い方について解説して行きます。
Mutationとは?
Mutationとは、GraphQLにおけるデータの更新方法です。
REST APIに置き換えるとpost, put, deleteにあたるような操作で、データベースの値を更新する時に使用されます。
Queryがgetの役割なので、それ以外がMutationになりますね。
コード紹介
ではサンプルコードをまず乗せて、Mutationを使用するときの要点を書いていきます。
AddTodo.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
import React from "react"; import gql from "graphql-tag"; import { Mutation } from "react-apollo"; const GET_TODOS = gql` { todos { id type } } `; const ADD_TODO = gql` mutation AddTodo($type: String!) { addTodo(type: $type) { id type } } `; const AddTodo = () => { let input; return ( <Mutation mutation={ADD_TODO} update={(cache, { data: { addTodo } }) => { const { todos } = cache.readQuery({ query: GET_TODOS }); cache.writeQuery({ query: GET_TODOS, data: { todos: todos.concat([addTodo]) } }); }} > {addTodo => ( <div> <form onSubmit={e => { e.preventDefault(); addTodo({ variables: { type: input.value } }); input.value = ""; }} > <input ref={node => { input = node; }} /> <button type="submit">Add Todo</button> </form> </div> )} </Mutation> ); }; export default AddTodo; |
Todos.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
import React from "react"; import gql from "graphql-tag"; import { Query, Mutation } from "react-apollo"; const GET_TODOS = gql` { todos { id type } } `; const UPDATE_TODO = gql` mutation UpdateTodo($id: String!, $type: String!) { updateTodo(id: $id, type: $type) { id type } } `; const Todos = () => ( <Query query={GET_TODOS}> {({ loading, error, data }) => { if (loading) return <p>Loading...</p>; if (error) return <p>Error :(</p>; return data.todos.map(({ id, type }) => { let input; return ( <Mutation mutation={UPDATE_TODO} key={id}> {updateTodo => ( <div> <p>{type}</p> <form onSubmit={e => { e.preventDefault(); updateTodo({ variables: { id, type: input.value } }); input.value = ""; }} > <input ref={node => { input = node; }} /> <button type="submit">Update Todo</button> </form> </div> )} </Mutation> ); }); }} </Query> ); export default Todos; |
App.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
import React, { Component } from 'react'; import './App.css'; import ApolloClient from "apollo-boost"; import { ApolloProvider } from "react-apollo"; import AddTodo from './components/AddTodo'; import Todos from './components/Todos'; const client = new ApolloClient({ uri: "https://8v9r9kpn7q.lp.gql.zone/graphql" // AddTodo }); class App extends Component { state = { selectedDog: null }; onDogSelected = ({ target }) => { this.setState(() => ({ selectedDog: target.value })); }; render() { return ( <ApolloProvider client={client}> <div> <h2>My first Apollo app 🚀</h2> <AddTodo/> <Todos/> </div> </ApolloProvider> ); } } export default App; |
create-react-appで生成したAppコンポーネント内からMutationを実行するAddTodo
, Todos
コンポーネントを呼び出しています。
実行すると、AddTodo
コンポーネントの出力結果としてAdd Todo
ボタンのついたフォームが表示され入力してクリックすると、入力したTODO内容とともにTodos
コンポーネントからUpdate Todo
ボタンのついたフォームが出力されます。
出力されたフォームに入力してボタンを押すと、Add Todo
で出力された文字が切り替わり、TODO内容が更新されます。
最初のフォームではGraphQLに対して値の追加、次のフォームでは値の更新処理が行われているのが分かります。
Mutationコンポーネント
Mutation
コンポーネントはUIからMutationを実行するためのコンポーネントです。
AddTodo
, Todos
コンポーネントのレンダリングメソッドからそれぞれ呼び出しています。
Mutation
コンポーネントのmutation
属性にクエリを渡すことで実行します。
variables
属性に値を渡すことでクエリに変数を持たせることもできます。
キャッシュの更新方法
Mutationでデータを追加・削除する場合、Apollo cacheは更新されないため、AddTodo
コンポーネントではupdate
メソッドでキャッシュに更新をかけています。
第一引数としてApollo cacheを使用でき、キャッシュのもつcache.readQuery
メソッドでキャッシュからデータを読み込み、追加したTODOと連結して、cache.writeQuery
メソッドでキャッシュを更新しています。
アップデートの指定をしたため、UIも自動的に更新されます。
TODOを更新した時にはupdate
メソッドは必要なく、画面は自動的に切り替わります。
更新時にはMutationを実行した時にできるtodoのデータがキャッシュに入れられ、クエリ結果が自動的に再構築されます。
以上となります!
データの追加・削除時にアップデートの指定をしないとキャッシュと画面が更新されない点は注意が必要ですね。