使用【React】和【ApolloClient】来访问GraphQL服务器

简介

    • ReactからGraphQLサーバにアクセスするためのClientライブラリとしてApolloClientがあります

 

    • 数年前にさわったことがありましたがHooks対応してかなり使いやすくなっていたのでセットアップとQuery/Mutationの叩き方を簡単に紹介します

 

    ※ApolloClientは執筆日時点(2020/3/28)でbeta版であるv3系を使っています

前期准备

    Reactの追加
yarn add react react-dom
    index.htmlの作成
<div id="root"></div>
<script src="index.js"></script>
    index.jsの作成
import React from 'react';
import { render } from 'react-dom';
import App from './src/App';

render(<App />, document.getElementById('root'));
    src/App.jsの作成
import React from 'react';

function App() {
  return (
    <div>
      <h1>Hello</h1>
    </div>
  );
}

export default App;
    • 起動

今回は手っ取り早く試すためParcelを使います

npx parcel-bundler index.html

http://localhost:1234 で起動します

ApolloClient的设置

    • ここからが本題です

 

    まずはライブラリを追加します
yarn add @apollo/client graphql
    • 次にGraphQLサーバのアクセス先などを設定します

ApolloClientの公式ページに登場するTODOアプリのGraphQLサーバを使っています
ブラウザで https://plp0mopxq.sse.codesandbox.io/ にアクセスするとPlaygroundでスキーマなどを確認できます

import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client';

export default new ApolloClient({
  cache: new InMemoryCache(),
  link: new HttpLink({
    uri: 'https://plp0mopxq.sse.codesandbox.io/graphql',
  }),
});

    App.jsに反映します
import React from 'react';
import { ApolloProvider } from '@apollo/client';
import client from './graphql/client';

function App() {
  return (
    <ApolloProvider client={client}>
      <h1>Hello</h1>
    </ApolloProvider>
  );
}

export default App;
    これでセットアップ完了です

执行查询

    • 実行するQueryを定義するファイルを作成します

Todoの全量を取得するGET_TODOSと、指定したIDのTodoを1件取得するGET_TODOの2つを定義します
Query実行時に引数を渡す場合はGET_TODOで定義しているような書き方をします

import { gql } from '@apollo/client';

// 全件取得
export const GET_TODOS = gql`
  query getTodos {
    todos {
      id
      type
    }
  }
`;

// 指定したIDのTODOを1件取得
export const GET_TODO = gql`
  query getTodo($id: String!) {
    todo(id: $id) {
      id
      type
    }
  }
`;

使用查询

    • コンポーネントからGET_TODOSのQueryを呼び出します

useQueryを使うとコンポーネントが生成された時にQueryが実行されます

今回のように一覧を取得して表示するようなケースで使うイメージですね
今回実行するGET_TODOSは引数なしですが、ありの場合はuseQueryの第2引数で指定することができます

useQuery(GET_TODOS, { variables: { xx: ‘xx’ } })

import React from 'react';
import { useQuery } from '@apollo/client';
import { GET_TODOS } from '../graphql/query';

function TodoList() {
  // Queryを実行
  const { loading, error, data } = useQuery(GET_TODOS);

  if (loading) return <p>...loading</p>;
  if (error) return <p>{error.message}</p>;

  return (
    <div>
      <h2>TodoList</h2>
      {data.todos.map(todo => (
        <p key={todo.id}>{todo.id}: {todo.type}</p>
      ))}
    </div>
  );
}

export default TodoList;
    App.jsに反映します
import React from 'react';
import { ApolloProvider } from '@apollo/client';
import client from './graphql/client';
// importを追加
import TodoList from './components/TodoList';

function App() {
  return (
    <ApolloProvider client={client}>
      <h1>Hello</h1>
      {/* コンポーネントを追加 */}
      <TodoList />
    </ApolloProvider>
  );
}

export default App;
todolist.gif

使用懒查询

    • IDを指定してTodoを1件取得するGET_TODOをコンポーネントから呼び出します

 

    • ユーザのアクションなどをきっかけにQueryを実行したい時はuseLazyQueryを使います

 

    Query実行時の引数は{ variables: {…} }といった形式でvariablesは固定文言でその中に必要な値をセットします
import React, { useRef } from 'react';
import { useLazyQuery } from '@apollo/client';
import { GET_TODO } from '../graphql/query';

function Todo() {
  const inputRef = useRef(null);
  // getTodoを呼び出すとQueryが実行される
  const [getTodo, { loading, error, data }] = useLazyQuery(GET_TODO);

  return (
    <div>
      <h2>Todo</h2>
      <div>
        <p>
          <input ref={inputRef} />
          {/* clickされたらgetTodoを実行する */}
          <button onClick={() => getTodo({ variables: { id: inputRef.current.value } })}>
            GET
          </button>
        </p>
        {loading && <p>...loading</p>}
        {error && <p>{error.message}</p>}
        {data && <p>ID: {data.todo.id}, Todo: {data.todo.type}</p>}
      </div>
    </div>
  );
}

export default Todo;
    App.jsに反映します
import React from 'react';
import { ApolloProvider } from '@apollo/client';
import client from './graphql/client';
import TodoList from './components/TodoList';
// importを追加
import Todo from './components/Todo';

function App() {
  return (
    <ApolloProvider client={client}>
      <h1>Hello</h1>
      <TodoList />
      {/* コンポーネントを追加 */}
      <Todo />
    </ApolloProvider>
  );
}

export default App;
todo.gif

进行突变

    • 実行するMutationを定義するファイルを作成します

Todoを追加するADD_TODOを定義します
引数の書き方はQueryの時と同じです

import { gql } from '@apollo/client';

export const ADD_TODO = gql`
  mutation AddTodo($type: String!) {
    addPlayer(type: $type) {
      id
      type
    }
  }
`;

使用useMutation

    • コンポーネントからMutationを実行してみます

useMutationから取得できるaddTodoを呼び出すとMutationを実行できます

import React, { useRef } from 'react';
import { useMutation } from '@apollo/client';
import { ADD_TODO } from '../graphql/mutation';

function AddTodo() {
  const inputRef = useRef(null);
  const [addTodo, { loading, error }] = useMutation(ADD_TODO);

  return (
    <div>
      <h2>AddTodo</h2>
      {loading && <p>...loading</p>}
      {error && <p>{error.message}</p>}
      <p>
        <input ref={inputRef} />
        {/* クリックしたらaddTodoを実行する */}
        <button onClick={() => addTodo({ variables: { type: inputRef.current.value } })}>
          ADD
        </button>
      </p>
    </div>
  );
}

export default AddTodo;
    App.jsに反映します
import React from 'react';
import { ApolloProvider } from '@apollo/client';
import client from './graphql/client';
import TodoList from './components/TodoList';
import Todo from './components/Todo';
// importを追加
import AddTodo from './components/AddTodo';

function App() {
  return (
    <ApolloProvider client={client}>
      <h1>Hello</h1>
      <TodoList />
      <Todo />
      {/* コンポーネントを追加 */}
      <AddTodo />
    </ApolloProvider>
  );
}

export default App;
add-todo.gif
    最後におまけで、追加したTodoを画面に反映させたいのでTodoListを再取得するボタンを追加します
import React from 'react';
import { useQuery } from '@apollo/client';
import { GET_TODOS } from '../graphql/query';

function TodoList() {
  // refetchを追加
  const { loading, error, data, refetch } = useQuery(GET_TODOS);

  if (loading) return <p>...loading</p>;
  if (error) return <p>{error.message}</p>;

  return (
    <div>
      <h2>TodoList</h2>
      {/* クリックするとデータを再取得する */}
      <button onClick={() => refetch()}>REFETCH</button>
      {data.todos.map(todo => (
        <p key={todo.id}>{todo.id}: {todo.type}</p>
      ))}
    </div>
  );
}

export default TodoList;
refetch.gif

总结

    • Aplloを使うとloadingの管理などもやってくれるため本当に便利ですね

 

    • とりあえずuseQuery, useLazyQuery, useMutationの3つが使えればだいたいのことはできると思います

 

    これらを使った実装がとても簡単だと実感してもらえていれば幸いです
广告
将在 10 秒后关闭
bannerAds