RelayContainer
是一个更高阶的 React 组件,它使 React 组件编码其数据需求。
使用 Relay.createContainer
创建 Relay 容器 。
Container 规范
属性和方法
在一般的 React 组件中,容器将会提供一些方法和属性做为this.props.relay
静态方法
fragments: RelayQueryFragments<Tk> = { [propName: string]: ( variables: {[name: string]: mixed} ) => Relay.QL`fragment on ...` };
容器声明 fragments
使用GraphQL片段的数据要求。
this.props
当渲染组件时,只有这些片段指定的字段才会被填充。这确保了组件在其父组件或任何子组件上没有隐式的依赖关系。
class StarWarsShip extends React.Component { render() { return <div>{this.props.ship.name}</div>; } } module.exports = Relay.createContainer(StarWarsShip, { fragments: { ship: () => Relay.QL` fragment on Ship { name } `, }, });
在此示例中,与 ship
片段相关联的字段将可用
this.props.ship
。
参见: 容器 > Relay 容器
initialVariables: {[name: string]: mixed};
此组件片段可用的初始变量值集。
class ProfilePicture extends React.Component {...} module.exports = Relay.createContainer(ProfilePicture, { initialVariables: {size: 50}, fragments: { user: () => Relay.QL` # The variable defined above is available here as '$size'. # Any variable referenced here is required to have been defined in initialVariables above. # An 'undefined' variable value will throw an 'Invariant Violation' exception. # Use 'null' to initialize unknown values. fragment on User { profilePicture(size: $size) { ... } } `, }, });
在这个例子中, profilePicture(size: 50)
将被提取为初始渲染。
prepareVariables: ?( prevVariables: {[name: string]: mixed} ) => {[name: string]: mixed}
容器可以定义一种 prepareVariables
提供修改可用于片段的变量的机会的方法。 除了运行时环境之外,还可以基于以前的变量(或者不存在先前的变量)生成新的变量。
在应用了部分变量集之后也会调用此方法 setVariables
。返回的变量用于填充片段。
module.exports = Relay.createContainer(ProfilePicture, { initialVariables: {size: 50}, prepareVariables: prevVariables => { return { ...prevVariables, // If devicePixelRatio is `2`, the new size will be `100`. size: prevVariables.size * window.devicePixelRatio, }; }, // ... });
shouldComponentUpdate: () => boolean;
RelayContainer 实现了一个传统的预设 shouldComponentUpdate
,在 fragment props 没有改变而且所有其他的 props 都是相等的值时会回传 false
。这可能会阻挡由 context 接收数据的 组件的更新。为了确保在这个状况能进行更新,可以通过指定一个 shouldComponentUpdate
函数覆写预设的行为。
module.exports = Relay.createContainer(ProfilePicture, { shouldComponentUpdate: () => true, // ... });
从被打包的 React 组件可以访问在 this.props.relay
下面列出的属性和方法。
route: RelayRoute
当一个组件在被渲染时,路由提供的上下文是非常有用的。它包含当下的路由有关 name
、params
、和 queries
的信息。
var name = this.props.relay.route.name; if (name === 'SuperAwesomeRoute') { // Do something super cool. }
可以参阅: 路由
variables: {[name: string]: mixed}
variables
包含用于获取当前 props 的变量集。
class ProfilePicture extends React.Component { render() { var user = this.props.user; return ( <View> <Image uri={user.profilePicture.uri} width={this.props.relay.variables.size} /> </View> ); } } module.exports = Relay.createContainer(ProfilePicture, { initialVariables: {size: 50}, fragments: { user: () => Relay.QL` fragment on User { profilePicture(size: $size) { ... } } `, }, });
在这个示例中,被渲染的图片 width
会对应到被用来获取目前 profilePicture.uri
版本所使用的 $size
变量。
附注
永远不要直接改动
this.props.relay.variables
,它不会正确的触发获取数据。把this.props.relay.variables
当作是不可变的来处理,就像 props 一样。
pendingVariables: ?{[name: string]: mixed}
pendingVariables
包含用于获取新 props 的一组变量,即何时 this.props.relay.setVariables()
或
this.props.relay.forceFetch()
被调用, 并且相应的请求在进行中。
如果没有请求在进行中,pendingVariables 为null
。
class ProfilePicture extends React.Component { requestRandomPictureSize = () => { const randIntMin = 10; const randIntMax = 200; const size = (Math.floor(Math.random() * (randIntMax - randIntMin + 1)) + randIntMin); this.props.relay.setVariables({size}); } render() { const {relay, user} = this.props; const {pendingVariables} = relay; if (pendingVariables && 'size' in pendingVariables) { // Profile picture with new size is loading return ( <View> <LoadingSpinner /> </View> ) } return ( <View> <Image uri={user.profilePicture.uri} width={relay.variables.size} /> <button onclick={this.requestRandomPictureSize}> Request random picture size </button> </View> ); } } module.exports = Relay.createContainer(ProfilePicture, { initialVariables: {size: 50}, fragments: { user: () => Relay.QL` fragment on User { profilePicture(size: $size) { ... } } `, }, });
在这个例子中,只要正在加载新尺寸的图片,就会显示一个调节框而不是图片。
setVariables([partialVariables: Object, [onReadyStateChange: Function]]): void
组件可以通过使用 setVariables
要求更新目前的 variables
组合,来改变它们的数据需求。
this.props.relay.setVariables
可以调用来同时更新子集或全部变量。作为返回,Relay 将使用新变量来尝试实现新的片段。如果客户端上的数据尚不可用,则可能会向服务器发送请求。
onReadyStateChange
可以提供可选的回调来响应数据执行所涉及的事件。
class Feed extends React.Component { render() { return ( <div> {this.props.viewer.feed.edges.map( edge => <Story story={edge.node} key={edge.node.id} /> )} </div> ); } _handleScrollLoad() { // Increments the number of stories being rendered by 10. this.props.relay.setVariables({ count: this.props.relay.variables.count + 10 }); } } module.exports = Relay.createContainer(Feed, { initialVariables: {count: 10}, fragments: { viewer: () => Relay.QL` fragment on Viewer { feed(first: $count) { edges { node { id, ${Story.getFragment('story')}, }, }, }, } `, }, });
Note
setVariables
不会立即变动variables
,但是会建立一个等待的状态。variables
会持续回传先前的值,直到满足新的变量值的数据填入了this.props
。
请参阅: 容器 > 请求不同的数据, 准备状态
forceFetch([partialVariables: Object, [onReadyStateChange: Function]]): void
forceFetch
类似于 setVariables
,因为它也可以用来通过修改 variables
来改变数据需求。
两种方法的区别在于,不是发送仅包含客户端缺少的字段的查询,而是发送 forceFetch
请求以重新获取每个片段。这确保组件的 props 从服务器获取最新的。
onReadyStateChange
e可以提供可选的回调来响应数据执行所涉及的事件。
附注
forceFetch
可以用一组空的部分变量来调用,这意味着它可以触发刷新当前渲染的数据集。
参见: 准备状态
hasOptimisticUpdate(record: Object): boolean
用一个从 this.props
来的记录调用 hasOptimisticUpdate
,会回传是否这个给定的记录有受到积极mutation 的影响。这让组件可以用不同的方式去渲染本地 积极变更和成功与服务器同步的数据。
class Feed extends React.Component { render() { var edges = this.props.viewer.feed.edges; return ( <div> {edges.map(edge => { var node = edge.node; if (this.props.relay.hasOptimisticUpdate(node)) { // Render pending story that has not been stored // on the server using a diffrent component. return ( <PendingStory key={edge.node.id} story={edge.node} /> ); } else { return ( <Story key={edge.node.id} story={edge.node} /> ); } })} </div> ); } } module.exports = Relay.createContainer(Feed, { initialVariables: {count: 10}, fragments: { viewer: () => Relay.QL` fragment on Viewer { feed(first: $count) { edges { node { id, ${Story.getFragment('story')}, ${PendingStory.getFragment('story')} } } } } `, }, });
可以参阅: Mutations > 积极更新
getPendingTransactions(record: Object): ?Array<RelayMutationTransaction>
组件可以对任何的记录(例如:在 props 上可以取用的数据与一个对应的片段)检查是否有待处理的 mutation。使用记录调用 getPendingTransactions
将会回传一个影响特定 记录 的待处理的 mutation事务列表。
每个 RelayMutationTransaction
都有检查 mutation 状态的方法,并提供了根据需要回滚或重新发送突变的方法。.
class Story extends React.Component { render() { var story = this.props.story; var transactions = this.props.relay.getPendingTransactions(story); // For this example, assume there is only one transaction. var transaction = transactions ? transactions[0] : null; if (transaction) { // Display an error message with a retry link if a mutation failed. if (transaction.getStatus() === 'COMMIT_FAILED') { return ( <span> This story failed to post. <a onClick={transaction.recommit}>Try Again.</a> </span> ); } } // Render story normally. } } module.exports = Relay.createContainer(ProfilePicture, { fragments: { story: () => Relay.QL` fragment on story { # ... } `, }, });
RelayMutationTransaction.getStatus
可以返回以下字符串之一:
UNCOMMITTED
— 事务尚未发送到服务器,可以回滚。
COMMIT_QUEUED
— 事务已提交,但具有相同冲突密钥的另一个事务处于挂起状态,因此事务已排队等待发送到服务器。
COLLISION_COMMIT_FAILED
— 事务已排队等待提交,但具有相同冲突键的另一个事务失败。碰撞队列中的所有事务(包括此事件)都已失败。可以重新提交或回滚事务。
COMMITTING
— 事务正在等待服务器的响应。COMMIT_FAILED
— 事务已发送到服务器进行配对,但是失败了。getFragment( fragmentName: string, variables?: {[name: string]: mixed} ): RelayFragmentReference
获取对子容器的片段的引用,以便包含在父片段中。
片段组成通过ES6模板串插值实现 getFragment
:
// Parent.js Relay.createContainer(Parent, { fragments: { parentFragment: () => Relay.QL` fragment on Foo { id ${Child.getFragment('childFragment')} } `, } }); // Child.js Relay.createContainer(Child, { initialVariables: { size: 64, }, fragments: { childFragment: () => Relay.QL` fragment on Foo { photo(size: $size) { uri } } `, } });
在这个例子中,每当 Parent
被获取时, Child
片段也将被获取。渲染时,<Parent>
只能访问该 props.foo.id
字段; 来自子片段的数据将被 屏蔽。默认情况下,
childFragment
将使用其对应的初始变量。Relay 将提取 photo(size:
64)
。 当 <Child>
被渲染它也将提供 props.relay.variables = {size: 64}
作为初始变量。
有时父进程需要覆写子组件的默认变量。想象一下,我们想要渲染 Child
上面的照片大小为128而不是默认值64。 为此,我们必须确保片段 和 容器都知道自定义变量。要在 查询 中设置自定义变量,请使用第二个参数
getFragment
:
// Parent.js Relay.createContainer(Parent, { fragments: { parentFragment: () => Relay.QL` fragment on Foo { id ${Child.getFragment('childFragment', {size: 128})} } `, } });
现在 Relay 将获取大小为 128 的照片 - 但 Child
容器不会神奇地知道这个变量。我们必须通过将变量值传递给一个 prop 来告诉它:
const Parent = (props) => { return ( <Child childFragment={props.parentFragment} size={128} />; ); }
现在 Relay 将获取较大的照片大小 , Child
并将知道渲染它。