解释(个人备忘录)relay的todo示例(正在撰写中)

alt

使用 `react-relay` 中的 `createFragmentContainer`、`QueryRenderer` 和 `graphql` 导入;
使用 `relay-runtime` 中的 `Environment`、`Network`、`RecordSource` 和 `Store` 导入。

解释以上的内容。 (预计需要一个小时)

1. 图灵请求语言 (GraphQL)

以下是定义GraphQL模板的方式。
尽管有一些参数和详细的使用方法,但基本上只需要定义查询。

import {graphql} from 'react-relay';

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

2. 环境

在此定义环境变量,参数包括NetWork、RecordSource和Store。Store和NetWork是必需的。可以定义不同的环境变量,并创建两个环境。在这里进行了与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,
});

三、网络

在这里编写与graphql服务器通信的设置。将编写的网络设置传递给环境。

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是位于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是一个HOC。该容器并不负责获取数据。然而,通过声明嵌套渲染,它会进行渲染。

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的组件和GraphQL时,可以使用createFragmentContainer来指定组件所需的数据。
简单来说,createFragmentContainer以组件的类名和GraphQL作为参数,创建一个具有通信功能的新容器。
(类似于Redux的connect和页面特定的saga的结合?)

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

在createFragmentContainer中,您可以通过props提取通过fetch获取的数据,如下所示。

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

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

创建RefetchContainer

创建碎片几乎相同。
创建碎片会在页面渲染时进行抓取。
但这里可以重新抓取。

当需要提前加载数据时,可以使用类似createFragments的方法来使用列表等数据。

传递商店

像是redux中的store一样的东西?好像有三种类型。
RecordSourceSelectorProxy
RecordProxy是用来改变record的接口
ConnectionHandler是用来处理关系的感觉?

数据源选择代理

RecordSourceSelectorProxy 接受哪种存储类型作为参数,其上来自以下的更新函数?

接口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 } can be paraphrased as:

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 }

以下是一个示例(translation: The following is an example)

以下为对原文的中文本地化改写,只提供一个选项:
const record = store.create(dataID, ‘待办事项’);
store.delete(dataID);
const record = store.get(dataID);
const root = store.getRoot();

首先,我们来讲解一下ToDo应用的功能。接下来是App.js文件的解释。

// react-relay
QueryRenderer,
graphql, -> // react-relay
QueryRenderer,
graphql,

// relay-runtime
环境,
网络,
记录源,
存储

广告
将在 10 秒后关闭
bannerAds