Relay 利用 GraphQL mutations; 使我们能够在客户端和服务器上变更数据的操作。要建立一个 mutation 在我们的应用程序中使用,我们必须继承 Relay.Mutation
并至少实现在下面的四个 抽象方法。
属性
方法
static fragments: RelayMutationFragments<$Keys<Tp>> // Type of RelayMutationFragments type RelayMutationFragments<Tk> = { [key: Tk]: FragmentBuilder; }; // Type of FragmentBuilder type FragmentBuilder = (variables: Variables) => RelayConcreteNode;
我们在这里声明我们的 mutations 数据依赖关系,就像我们用容器一样。这对于用来确保我们可能会想要在这个 mutation 的积极响应中使用的一组字段已经被获取特别有用。
class LikeStoryMutation extends Relay.Mutation { static fragments = { story: () => Relay.QL` fragment on Story { likers { count }, viewerDoesLike, } `, }; getOptimisticResponse() { // this.props.story.likers.count and this.props.story.viewerDoesLike // are guaranteed to have been fetched since we've declared // them to be part of this mutation's data dependencies above. return { /* ... */ }; } }
参见: Mutations > Fragment 变量 and Mutations > 积极更新
static initialVariables: {[name: string]: mixed};
我们在这里指定的默认值将可用于我们的片段构建:
class ChangeTodoStatusMutation extends Relay.Mutation { static initialVariables = {orderby: 'priority'}; static fragments = { todos: () => Relay.QL` # The variable defined above is available here as $orderby fragment on User { todos(orderby: $orderby) { ... } } `, }; /* ... */ }
static prepareVariables: ?( prevVariables: {[name: string]: mixed}, route: RelayMetaRoute, ) => {[name: string]: mixed} // Type of `route` argument type RelayMetaRoute = { name: string; }
如果我们提供给 mutation 一个方法符合上面所描述的 signature,它会有一个机会基于先前的变量 (或是如果前面没有的话会是 initialVariables
)、meta 路由、和执行期环境,去调整 fragment 构建的变量。无论这个方法回传什么变量都会可以在这个 mutation 的 fragment 构建取用。
class BuySongMutation extends Relay.Mutation { static initialVariables = {format: 'mp3'}; static prepareVariables = (prevVariables) => { var overrideVariables = {}; var formatPreference = localStorage.getItem('formatPreference'); if (formatPreference) { overrideVariables.format = formatPreference; // Lossless, hopefully } return {...prevVariables, overrideVariables}; }; /* ... */ }
使用 new
关键词建立一个 mutation 实例,可选地传递给它一些 this.props
。要注意的是,this.props 在 函数里面是不可取用的,不过在所有下面提到的方法 (getCollisionKey、getOptimisticResponse,等等) 都是设置好的。 这种限制是由于 mutation props 可能取决于 Relay 环境的数据,直到 mutation 应用于 applyUpdate
或 commitUpdate
。
var bookFlightMutation = new BuyPlaneTicketMutation({airport: 'yvr'}); Relay.Store.commitUpdate(bookFlightMutation);
abstract getConfigs(): Array<{[key: string]: mixed}>
实现这个必要的方法来给出 Relay 指令,说明如何使用每个 mutation 的响应有效载荷来更新客户端存储。
class LikeStoryMutation extends Relay.Mutation { getConfigs() { return [{ type: 'FIELDS_CHANGE', fieldIDs: { story: this.props.story.id, }, }]; } }
abstract getFatQuery(): GraphQL.Fragment
实现这个必要的方法来设计一个 ‘fat 查询’ – 代表数据模型中可能由于这种 mutation 而改变的每个字段。
class BuySongMutation extends Relay.Mutation { getFatQuery() { return Relay.QL` fragment on BuySongPayload { songs { count, edges, }, totalRunTime, } `, } }
abstract getMutation(): GraphQL.Mutation
实现必要的方法来返回表示要执行的突变的GraphQL mutation 操作。
class LikeStoryMutation extends Relay.Mutation { getMutation() { return this.props.story.viewerDoesLike ? return Relay.QL`mutation {unlikeStory}` : return Relay.QL`mutation {likeStory}`; } }
abstract getVariables(): {[name: string]: mixed}
实现这个必要的方法来准备变量作为 mutation 的输入。
class DestroyShipMutation extends Relay.Mutation { getVariables() { return { // Assume that the server exposes a `destroyShip` mutation // that accepts a `shipIDToDestroy` variable as input: shipIDToDestroy: this.props.ship.id, }; } }
警告
这里的术语“变量”是指对服务器端 mutation 的输入,而不是这个 mutation 的片段构建可用的变量。
static getFragment( fragmentName: $Keys<Tp>, variableMapping?: Variables ): RelayFragmentReference // Type of the variableMapping argument type Variables = {[name: string]: mixed};
获取用于父查询片段的片段引用。
class StoryComponent extends React.Component { /* ... */ static fragments = { story: () => Relay.QL` fragment on Story { id, text, ${LikeStoryMutation.getFragment('story')}, } `, }; }
您还可以从包含它的外部片段将变量传递给 mutation 的片段构建器。
class Movie extends React.Component { /* ... */ static fragments = { movie: (variables) => Relay.QL` fragment on Movie { posterImage(lang: $lang) { url }, trailerVideo(format: $format, lang: $lang) { url }, ${RentMovieMutation.getFragment('movie', { format: variables.format, lang: variables.lang, })}, } `, }; }
提示
在最后的一个例子中,把
$format
和variables.format
想成是一样的值。
getCollisionKey(): ?string
实现此方法返回冲突键。Relay 将向服务器发送具有相同冲突密钥的任何突变顺序和顺序。
class LikeStoryMutation extends Relay.Mutation { getCollisionKey() { // Give the same key to like mutations that affect the same story return `like_${this.props.story.id}`; } }
getFiles(): ?FileMap // Type of the FileMap object type FileMap = {[key: string]: File};
实现这个方法来回传一个要上传的 File
对象的映射作为 mutation 的一部份。
class AttachDocumentMutation extends Relay.Mutation { getFiles() { return { file: this.props.file, }; } } class FileUploader extends React.Component { handleSubmit() { var fileToAttach = this.refs.fileInput.files.item(0); Relay.Store.commitUpdate( new AttachDocumentMutation({file: fileToAttach}) ); } }
getOptimisticConfigs(): Array<{[key: string]: mixed}>
在需要处理积极响应的mutator 配置需要与处理服务器响应的 mutator 配置不同的实现方法。
参阅: Relay.Mutation::getConfigs()
getOptimisticResponse(): ?{[key: string]: mixed}
实现此方法来制作与服务器响应有效负载相同情形的积极响应。这种积极的响应将用于在服务器返回之前抢先更新客户端缓存,从而给出瞬时完成 mutation 的印象。
class LikeStoryMutation extends Relay.Mutation { getOptimisticResponse() { return { story: { id: this.props.story.id, likers: { count: this.props.story.likers.count + 1, }, viewerDoesLike: !this.props.story.viewerDoesLike, }, }; } }
参阅: Mutations > 积极更新