Containers #Facebook Relay文档翻译#

原文地址:Containers
上一篇 Tutorial
Relay文档翻译目录

The primary way to declare data requirements is via Relay.Container — a higher-order React component that lets React components encode their data requirements.
在Relay中主要通过Relay.Container来声明数据需求,它是高阶React component,用于让React component描述自己的数据需求。所谓高阶,如同高阶函数可以接收一个函数作为参数,同样的它可以接收一个React component作为参数。

Similar to how a React component’s render method does not directly modify native views, Relay containers do not directly fetch data. Instead, containers declare a specification of the data needed to render. Relay guarantees that this data is available before rendering.
我们都知道React component的render方法并没有直接修改真实的dom节点,而是通过virtual dom等技术实现。与之类似,Relay containers并不是直接获取数据。取而代之的是,containers声明需要render的数据说明。Relay保证在数据被渲染以前是可用的。

A Complete Example

To start, let’s build the plain React version of a <ProfilePicture> component that displays the user’s profile photo and a slider to adjust the photo’s size.
一开始,我们先构建一个纯React版的<ProfilePicture> component,用于显示用户简介中的照片,还有一个滑动条可以调整照片大小。

Base React Component

Here’s a basic implementation of <ProfilePicture> that ignores styling in order to highlight the functionality:
下面是<ProfilePicture>的基本实现,为突出功能忽略了css style

class ProfilePicture extends React.Component {
  render() {
    // Expects the `user` prop to have the following shape:
    // {
    //   profilePhoto: {
    //     uri,
    //     size
    //   }
    // }
    var user = this.props.user;
    return (
      <View>
        <Image uri={user.profilePhoto.uri} width={...} />
        <Slider onChange={value => this.setSize(value)} />
      </View>
    );
  }

  // Update the size of the photo
  setSize(photoSize) {
    // TODO: Fetch the profile photo URI for the given size...
  }
}

Data Dependencies With GraphQL

In Relay, data dependecies are described using GraphQL. For <ProfilePicture>, the dependency can be expressed as follows. Note that this exactly matches the shape that the component expected for the user prop.
在Relay中使用 GraphQL描述数据依赖关系。<ProfilePicture>的依赖关系见下面代码。它精确的匹配了component上的数据需求,此例映射到user prop上。

Relay.QL`
  # This fragment only applies to objects of type `User`.
  fragment on User {
    # Set the `size` argument to a GraphQL variable named `$size` so that we can
    # later change its value via the slider.
    profilePhoto(size: $size) {
      # Get the apppropriate URI for the given size, for example on a CDN.
      uri,
    },
  }
`

注释:译者在下面代码中进行了解读,帮助理解

Relay Containers

Given the plain React component and a GraphQL fragment, we can now define a Container to tell Relay about this component’s data requirements. Let’s look at the code first and then see what’s happening:
给出了纯的React component和一个GraphQL fragment。我们现在可以定义一个Container来告诉Relay那个纯的React component的数据需求。

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

// Export a *new* React component that wraps the original `<ProfilePicture>`.
// Relay.createContianer接收一个ProfilePicture component,返回一个新的React component,并且将其输出。
module.exports = Relay.createContainer(ProfilePicture, {
  // Specify the initial value of the `$size` variable.
  // initialVariables中可以初始化一些变量
  initialVariables: {
    size: 32
  },
  // For each of the props that depend on server data, we define a corresponding
  // key in `fragments`. Here, the component expects server data to populate the
  // `user` prop, so we'll specify the fragment from above as `fragments.user`.
  // 对于每一个依赖服务器端数据的prop,我们在fragments中定义一个相应的key,
  // 这里component期望服务器端获取数据放入user prop,所以我们把之前上面那段代码,放入到fragments.user中。
  // fragments对象中的每个属性,这里如user,都可以在与之绑定的React Component(这里是ProfilePicture)中的props中获取,这里是this.props.user
  fragments: {
    user: () => Relay.QL`
      fragment on User {
      #在服务器端schema中一定有对应的User
        profilePhoto(size: $size) {
        #在schema User下一定有方法profilePhoto
          uri,
          #该方法一定有对应的返回值
        },
      }
    `,
  },
});

为了便于理解,可以对照schema一起看

Containers are Higher-Order Components

Relay containers are higher-order components — Relay.createContainer is a function that takes a React component as input and returns a new component as output. This means that the container can manage data fetching and resolution logic without interfering with the state of the inner component.
Relay container 是高阶componet。Relay.createContainer是一个函数可以接收React component作为输入,返回一个新的component作为输出。这意味着container可以管理数据获取和解析逻辑,并且不需要使用组件内部的state。(注:这是一个巨大的好处)

Here’s what happens when the container is rendered:
这里展示了当container进行render的时候发生了什么:

这里写图片描述

In the diagram above:

  • A parent component will pass in a reference to some User “record”.
  • The container — named Relay(ProfilePicture) for debugging — will retrieve the response for each GraphQL fragment from the local store.
  • The container passes the results of each fragment (along with the other props) to the <ProfilePicture> component.
  • <ProfilePicture> receives a user prop with plain JavaScript data - objects, arrays, strings - and renders as usual.
  • 从父component传来一些User记录的引用
  • Relay(ProfilePicture)这个container将通过每一个GraphQL fragment从本地的store中获取返回值
  • 这个container将每一个fragment的返回值及其他一些props一同传给<ProfilePicture> component
  • <ProfilePicture> 接收到一个user prop,其中包含着普通的JS数据,如object,arrays, string,之后像原来一样render

Requesting Different Data

One thing is left in the example above — implementing setSize(), which should change the photo’s size when the slider values changes. In addition to passing the results of each query to the component, Relay also provides a relay prop that has Relay-specific methods and metadata. These include variables — the active variables used to fetch the current props — and setVariables() — a callback that can be used to request data for different variable values.
上面例子中还有一件事要做,实现setSize()方法,当slider变动时可以改变照片size。除了可以传递query结果给component,Relay还提供了’relay’ prop,其中还有Relay定制的方法与元数据。variables就是其中一个,用于获取当前props,setVariables()是一个回调用于为不同的变量值请求数据。

class ProfilePicture extends React.Component {
  render() {
    // Access the resolved data for the `user` fragment.
    // 访问user fragment的返回数据
    var user = this.props.user;
    // Access the current `variables` that were used to fetch the `user`.
    var variables = this.props.relay.variables;
    return (
      <View>
        <Image
          uri={user.profilePhoto.uri}
          width={variables.size}
        />
        <Slider onChange={value => this.setSize(value)} />
      </View>
    );
  }

  // Update the size of the photo.
  setSize(photoSize) {
    // `setVariables()` tells Relay that the component's data requirements have
    // changed. The value of `props.relay.variables` and `props.user` will
    // continue to reflect their previous values until the data for the new
    // variables has been fetched from the server. As soon as data for the new
    // variables becomes available, the component will re-render with an updated
    // `user` prop and `variables.size`.
    this.props.relay.setVariables({
      size: photoSize,
    });
  }
}

Container Composition

React and Relay support creating arbitrarily complex applications through composition. Larger components can be created by composing smaller components, helping us to create modular, robust applications. There are two aspects to composing components in Relay:
React和Relay支持通过composition的方式创建任意复杂的应用。大一些的component可以由小的component构成,这有助于建立模块化的、健壮的应用。在Relay中构建component包括以下两个方面:

  • Composing the view logic, and 构建视图逻辑
  • Composing the data descriptions. 构建数据描述

Let’s explore how this works via a <Profile> component that composes the <ProfilePicture> from above.
我们通过看<Profile>如何使用之前<ProfilePicture>进行构建做进一步了解。

Composing Views - It’s Plain React

View composition is exactly what you’re used to — Relay containers are standard React components. Here’s the <Profile> component:
视图构建和你已经习惯的react中的工作方式一模一样,Relay container就是标准的React component。以下是<Profile> component

class Profile extends React.Component {
  render() {
    // Expects a `user` with a string `name`, as well as the information
    // for `<ProfilePicture>` (we'll get that next).
    var user = this.props.user;
    return (
      <View>
        {/* It works just like a React component, because it is one! */}
        <ProfilePicture user={user} />
        <Text>{user.name}</Text>
      </View>
    );
  }
}

Composing Fragments

Fragment composition works similarly — a parent container’s fragment composes the fragment for each of its children. In this case, <Profile> needs to fetch information about the User that is required by <ProfilePicture>.
Fragment composition工作方式类似,父container的fragment由包含的子fragment构成。在这个例子中<Profile>获取被<ProfilePicture>需要的User数据。

Relay containers provide a static getFragment() method that returns a reference to that component’s fragment:
Relay containers 提供了一个静态方法getFragment()参数接收一个子fragment的属性,返回该子fragment的引用。

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

module.exports = Relay.createContainer(Profile, {
  fragments: {
    // This `user` fragment name corresponds to the prop named `user` that is
    // expected to be populated with server data by the `<Profile>` component.
    user: () => Relay.QL`
      fragment on User {
        # Specify any fields required by `<Profile>` itself.
        name,

        # Include a reference to the fragment from the child component. Here,
        # the `user` is the name of the fragment specified on the child
        # `<ProfilePicture>`'s `fragments` definition.
        ${ProfilePicture.getFragment('user')},
      }
    `,
  }
});

The final data declaration is equivalent to the following plain GraphQL:
上面最后那段数据声明等同于如下普通GraphQL

`
  fragment Profile on User {
    name,
    ...ProfilePhoto,
  }

  fragment ProfilePhoto on User {
    profilePhoto(size: $size) {
      uri,
    },
  }
`

Note that when composing fragments, the type of the composed fragment must match the field on the parent in which it is embedded. For example, it wouldn’t make sense to embed a fragment of type Story into a parent’s field of type User. Relay and GraphQL will provide helpful error messages if you get this wrong (and if they aren’t helpful, let us know!).
注意当构建fragment的时候,被用来构建的fragment type必须与其父上的field匹配。例如,把Storytype 对应到其父的User type field。Relay和GraphQL将提供辅助的错误提示。

Rendering Containers

As we’ve learned, Relay containers declare data requirements as GraphQL fragments. This means that, for example, <ProfilePicture> can be embedded not only in <Profile>, but any container that fetches a field of type User.
正如我们所学,Relay container通过GraphQL fragment来声明数据需求。这意味着,如<ProfilePicture>不仅可以被嵌在<Profile>中,而是任何使用User type field的container都可以。

We’re almost ready to let Relay fulfill the data requirements for these components and render them. However, there is one problem. In order to actually fetch data with GraphQL, we need a query root. For example, we need to ground the <Profile> fragment in a concrete node of type User.
我们几乎快要全部满足这些组件的数据需求并可以渲染他们了。但是还有一个问题。为了切实的通过GraphQL获取数据,我们还需要一个query root。例如,我们需要把<Profile>对应到具体的User type node上。

In Relay, the root of a query is defined by a Route. Continue to learn about Relay routes.
在Relay中,使用Route定义查询的根,我们随后继续学习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值