0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

relayのtodo exampleを解説(超個人的メモ)(執筆途中)

Last updated at Posted at 2018-07-16

alt
relayのtodo exampleを見てみた。
以下が、importされていた。ということは以下の要素を読み解けばrelayが何かわかるはずだ。

import {
createFragmentContainer,
QueryRenderer,
graphql,
} from 'react-relay';
import {
Environment,
Network,
RecordSource,
Store,
} from 'relay-runtime';

以上のものを解説していく。 (一時間を予定)

1.graphql

以下のようにgraphqlのテンプレートを定義する。
引数など、細かな使い方はあるが、基本的にはクエリを定義するだけ。

import {graphql} from 'react-relay';

graphql`
  query MyQuery {
    viewer {
      id
    }
  }
`;

2.Environment

環境変数を定義する。 引数は NetWork, RecordSource, Store
storeとnetworkは必須。別々の環境変数を定義して、二つのEnvironmentを作成することも可能。
graphqlサーバーと通信するための設定を全てここで行う。

const {
  Environment,
  Network,
  RecordSource,
  Store,
} = require('relay-runtime');

const source = new RecordSource();
const store = new Store(source);
const network = Network.create(/*...*/); // see note below
const handlerProvider = null;

const environment = new Environment({
  handlerProvider, // Can omit.
  network,
  store,
});

3.Network

graphqlサーバと通信するための設定をここに書く。書いたNetWorkはEnvironmentに食わせる

import {
  Environment,
  Network,
  RecordSource,
  Store,
} from 'relay-runtime';

// Define a function that fetches the results of an operation (query/mutation/etc)
// and returns its results as a Promise:
function fetchQuery(
  operation,
  variables,
  cacheConfig,
  uploadables,
) {
  return fetch('/graphql', {
    method: 'POST',
    headers: {
      // Add authentication and other headers here
      'content-type': 'application/json'
    },
    body: JSON.stringify({
      query: operation.text, // GraphQL text from input
      variables,
    }),
  }).then(response => {
    return response.json();
  });
}

// Create a network layer from the fetch function
const network = Network.create(fetchQuery);
const store = new Store(new RecordSource())

const environment = new Environment({
  network,
  store
  // ... other options
});

export default environment;

4.queryRenderer

queryRendererはrelayコンポーネントツリーの頂上にあるコンポーネントです。
queryとfetchを受け取り、結果をpropsとしてレンダリングします。
reduxのproviderのような役割のものかな?

import React from 'react';
import { QueryRenderer, graphql } from 'react-relay';

class Example extends React.Component {
  render() {
    return (
      <QueryRenderer
        environment={environment}
        query={graphql`
          query ExampleQuery($pageID: ID!) {
            page(id: $pageID) {
              name
            }
          }
        `}
        variables={{
          pageID: '110798995619330',
        }}
        render={({error, props}) => {
          if (error) {
            return <div>{error.message}</div>;
          } else if (props) {
            return <div>{props.page.name} is great!</div>;
          }
          return <div>Loading</div>;
        }}
      />
    );
  }
}

5.FragmentContainer

FragmentContainerはHOCです。このcontainerはdataをfetchするわけではありません。しかし、ネストされたレンダリングを宣言することでレンダリングします。

createFragmentContainer(
  component: ReactComponentClass,
  fragmentSpec: GraphQLTaggedNode | {[string]: GraphQLTaggedNode},
): ReactComponentClass;

以上の例だと何をしているかわからないですね。以下でもっと実践的な例を見てみます。
TodoItemコンポーネントがあると仮定します。このコンポーネントはtextと、todoが完了したかのstatusを持ちます。

// TodoItem.js
class TodoItem extends React.Component {
  render() {
    // Expects the `item` prop to have the following shape:
    // {
    //   item: {
    //     text,
    //     isComplete
    //   }
    // }
    const item = this.props.item;
    return (
      <View>
        <Checkbox checked={item.isComplete} />
        <Text>{item.text}</Text>
      </View>
    );
  }
}

relayではデータ依存はGraphqlを使って解決します。依存は以下のように解決されます。

graphql`
  # This fragment only applies to objects of type 'Todo'.
  fragment TodoItem_item on Todo {
    text
    isComplete
  }
`
import {createFragmentContainer, graphql} from 'react-relay';

class TodoItem extends React.Component {/* as above */}

// Export a *new* React component that wraps the original `<TodoItem>`.
export default createFragmentContainer(TodoItem, {
  // For each of the props that depend on server data, we define a corresponding
  // key in this object. Here, the component expects server data to populate the
  // `item` prop, so we'll specify the fragment from above at the `item` key.
  item: graphql`
    fragment TodoItem_item on Todo {
      text
      isComplete
    }
  `,
});

以上のようにreactのcomponentとgraphqlが与えられた時、createFragmentContainerでcomponentが要求するデータを指定できます。
要するにcreateFragmentContainerはcomponentのclass名とgraphqlを引数にとり、通信機能をもつ新しい
containerを作ります。(reduxのconnectとページ固有のsagaが一緒になった感じ?)

export default createFragmentContainer(
  TodoItem,
  graphql`
    fragment TodoItem_item on Todo {
      text
      isComplete
    }
  `,
);

createFragmentContainerの中でfetchしたデータは以下のようにpropsで取り出せます。

class TodoItem extends React.Component {
  render() {
    const item = this.props.data;
    // ...
  }
}

export default createFragmentContainer(
  TodoItem,
  graphql`
    fragment TodoItem on Todo {
      text
      isComplete
    }
  `,
);

createRefetchContainer

createFragmentsとほぼ同じ。
createFragmentsはページがレンダリングされるときにfetchする。
ただこちらはrefetchができる。

createFragmentsとほぼ同じ
リストなどで、データを先に読み込んでおきたい時に使う。

Relay Store

reduxのstoreのようなもの? なんか3種類あるみたい。
RecordSourceSelectorProxy
RecordProxy recordをmutateするインターフェース
ConnectionHandler relationを扱う感じ?

RecordSourceSelectorProxy

RecordSourceSelectorProxyは以下のupdater functionを引数にとるstoreのタイプ?

interface RecordSourceSelectorProxy {
create(dataID: string, typeName: string): RecordProxy;
delete(dataID: string): void;
get(dataID: string): ?RecordProxy;
getRoot(): RecordProxy;
getRootField(fieldName: string): ?RecordProxy;
getPluralRootField(fieldName: string): ?Array;
}

以下は例

const record = store.create(dataID, 'Todo');
store.delete(dataID);
const record = store.get(dataID);
const root = store.getRoot();

それではtodoアプリの解説を書いていく。
まず、App.js

// react-relay
QueryRenderer,
graphql,

// relay-runtime
Environment,
Network,
RecordSource,
Store,

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?