LoginSignup
6
4

More than 3 years have passed since last update.

Hasura, Apollo, Reactでsubscriptionsのリアルタイム更新の実装

Posted at

メモ書き
需要が有れば書き直します。

実装コード

httpの通信からWebSocketの通信に切り替える必要があるのでプラグインのインストール

yarn add subscriptions-transport-ws

WebSocketLinkを使ってApolloClientのlinkをwsに変える

uriでhttp指定していたURIがhttp://localhost:8080/v1/graphqlであった
WebSocketで双方向に通信したいのでws://localhost:8080/v1/graphqlに書き換える。

この時、Hasura側では特に何もする必要はない。

index.tsx
import {
  ApolloClient,
  InMemoryCache,
  gql
} from "@apollo/client";
import { WebSocketLink } from "@apollo/client/link/ws";
import { useSubscription } from '@apollo/react-hooks'
import ArticleCards from '../components/ArticleCards'

const client = new ApolloClient({
  // uriをlinkに変更(http通信からws通信にする)
  link: new WebSocketLink({
    uri: 'ws://localhost:8080/v1/graphql',
    options: {
      reconnect: true,
       connectionParams: {
          headers: {
            // 認証系はここに書く
          }
       }
    }
  }),
  cache: new InMemoryCache(),
 });

export default function Home() {
  return (
    <ApolloProvider client={client}>
      <ArticleCards></ArticleCards>
    </ApolloProvider>
  );
}

記事一覧のコンポーネント(雑につくった)でリアルタイム更新

useQueryを使っていた場合は、useSubscriptionに書き換える。
gqlのコード以外は特に変わらないので説明は割愛

ArticleCards.tsx
import { useSubscription } from '@apollo/react-hooks'
import Card from "@material-ui/core/Card";
import CardActions from "@material-ui/core/CardActions";
import CardContent from "@material-ui/core/CardContent";
import Button from "@material-ui/core/Button";
import Typography from "@material-ui/core/Typography";
import articleStyle from '../styles/ArticleCards.module.css';

import { ARTICLES_SUBSCRIPTIONS } from '../gql/articles';

interface ArticleType {
  id: string;
  text: string;
}

const Article = (article: ArticleType) => {
  return (
    <Card variant="outlined" className={articleStyle.card}>
      <CardContent>
        <Typography variant="body2" component="p">
          {article.text}
        </Typography>
      </CardContent>
      <CardActions>
        <Button size="small">MORE</Button>
      </CardActions>
    </Card>
  );
}

const ArticleCards = () => {
  const { loading, error, data} = useSubscription(ARTICLES_SUBSCRIPTIONS);
  console.log(data)
  // ローディング中の表示
  if (loading) return <p>loading</p>
  // エラー時の表示
  if (error) return <p>{error.toString()}</p>
  // 成功してデータが帰ってきた時の表示
  return (
    <div className={articleStyle.article}>
      {data.articles.map((article: ArticleType) => (
        <Article {...article} key={article.id}></Article>
      ))}
    </div>
  );
}

export default ArticleCards

gqlでsubscriptionsを書く

参考までにquery, subscription, mutationを書いておいた。

gql/articles.ts
import gql from "graphql-tag";

export const ARTICLES_QUERY = gql`
  query {
    articles {
      id
      text
    }
  }
`;

export const ARTICLES_SUBSCRIPTIONS = gql`
  subscription ArticlesSubscriptions {
    articles(limit: 30, order_by: { created_at: asc }) {
      date
      id
      text
    }
  }
`;

export const ADD_ARTICLES = gql`
  mutation AddArticles($text: String = "", $date: date = "") {
    insert_articles(objects: { text: $text, date: $date }) {
      returning {
        id
        text
        date
      }
    }
  }
`;

参考記事

Hasura/GraphQL/React.js/Subscriptions
https://hasura.io/learn/graphql/react/subscriptions/1-subscription/

Hasura/GraphQL/Vue.js/Subscriptions
https://hasura.io/learn/graphql/vue/subscriptions/1-subscription/

WebSocketとは?
https://www.keicode.com/script/html5-websocket-1.php

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4