LoginSignup
0
0

More than 3 years have passed since last update.

ReactでApollo-clientを用いてGraphQLでデータ取得するClassコンポーネント

Last updated at Posted at 2020-02-13

背景

ReactにてGraphQLでデータ取得したい、かつ、クラスベースコンポーネントをTypeScriptで実装したいが、Appolo-Client公式のサンプルコードがどうしても動かなかったのでそのメモ。あと、細かいところがどうしてもわからなかったのでどなたかコメントくれたら嬉しいなという期待を込めて。

この記事で書かないこと

GraphQL、React、Typescript、サーバサイドの実装について

サンプルコード

まずはサンプルコードからお見せします。サーバサイドは、termという検索キーワード的な文字列を受け取ってid, title, descriptionのリストを返すイメージです。

Works.tsx
import React from "react";
import { graphql, ChildProps } from "react-apollo";
import gql from "graphql-tag";

const query = gql`
  query GetWorks($term: String) {
    works(term: $term) {
      id
      title
      description
    }
  }
`;

interface Work {
  id: string;
  title: string;
  description: string;
}

interface Response {
  works: Work[];
}
type Variables = {
  term: string | undefined;
};

interface InputProps extends Variables {}

type Props = ChildProps<InputProps, Response, Variables>;

const ChildWorks = graphql<InputProps, ResWorks, Variables, Props>(query, {
  options: ({ term }) => ({
    variables: { term }
  }),
  props: ({ data, ownProps }) => ({ data, ...ownProps })
});

class _Works extends React.Component<Props, {}> {
  renderWorks(): JSX.Element[] {
    if (this.props.data) {
      const { loading, works, error } = this.props.data;
      if (loading) return [<div key={0}>Loading...</div>];
      if (error) return [<div key={0}>ERROR</div>];
      if (works) {
        return works.map(work => {
          return (
            <div key={work.id}>
              <h2>{work.title}</h2>
              <p>{work.description}</p>
            </div>
          );
        });
      } else {
        return [<div key={0}>nothing</div>];
      }
    } else {
      return [<div key={0}>loading...</div>];
    }
  }

  render(): JSX.Element {
    return <div>{this.renderWorks}</div>;
  }
}

export const Works = ChildWorks(_Works);

あとはコンポーネントとして利用できるので、どこかで

App.tsx
<Work term={何かstring} />

としてあげれば実行できます。

説明(可能な部分)

ResponseのTypeとVariableのType、PropsのTypeを指定しています。
InputPropsが空になっていますが、Variableに含めないがPropsとして呼び出し元から値を取りたい場合にはここに追記します。今回はProps=Variablesの前提にしているので空です。

interface Work {
  id: string;
  title: string;
  description: string;
}

interface Response {
  works: Work[];
}
type Variables = {
  term: string | undefined;
};

interface InputProps extends Variables {}

type Props = ChildProps<InputProps, Response, Variables>;

optionsの部分でPropsで受け取った値をVariablesにセットしています。
propsの部分はなぜこういう記述になるのかは不明、、、どこか海外のサンプルコードから引っ張ってきたはずですがましたが、参照元のURLもすでにわからず。

const ChildWorks = graphql<InputProps, ResWorks, Variables, Props>(query, {
  options: ({ term }) => ({
    variables: { term }
  }),
  props: ({ data, ownProps }) => ({ data, ...ownProps })
});

GraphQLで取得したデータはthis.props.dataからアクセスできます。

const { loading, works, error } = this.props.data;

定義したReactコンポーネントそのままでは利用できず、さっき定義したChildWorksでラップしてあげる必要があるらしい。クエリとクラスコンポーネントを結びつけてあげるイメージかなと。

export const Works = ChildWorks(_Works);

一応、上記で動作してます。

JSXの配列をreturnする際にkeyを設定しないとWarningが出るので無理やりkey={0}で回避しているのですが、これもどうにかできないものか。。。

0
0
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
0
0