Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

magically refetches relevant apollo graphql queries after creates, deletes, and association changes

License

NotificationsYou must be signed in to change notification settings

jcoreio/apollo-magic-refetch

Repository files navigation

CircleCICoverage Statussemantic-releaseCommitizen friendlynpm version

Handling Apollo cache updates after creating and deleting objects, orassociating and dissociating objects, remains apoorly solved problem.update andrefetchQueries props onMutations couple different areas ofyour app in a way you probably don't want, and they don't scale well as you addmore queries over objects you may create/delete.

Truly solving the problem will probably require changes to the apollo clientand cache code.

Until that happens, this is probably your best bet!

Table of Contents

How it works

After you delete an object, you tellapollo-magic-refetch whattypename andid was deleted, and it refetches all active queries that contain that objectanywhere within their current data!

Similarly, after you create an object, you tell it thetypename of the createdobject and it refetches all active queries that contain an object of that typein their selections. This is a bit less efficient than handling deletes, butway easier than anything else at the time of writing.

Since only active queries can be refetched, data in the cache for inactivequeries will remain out-of-date. For that reason, I would recommend using thecache-and-network policy on all queries you're not planning toupdate afterall pertinent mutations.

Current limitations

  • Interfaces and union types are not supported yet. This means if they areanywhere in your results, this library may fail to refetch when it should.
  • Lists of lists are not supported yet.

ES environment requirements

If you are building for legacy browsers with a bundler like Webpack, make sureto add a rule to transpile this package to ES5.

If you are not using a bundler that supports themodule property inpackage.json, make sure to installbabel-runtime.

Type metadata usage

apollo-magic-refetch uses type metadata from GraphQL determine which queriesneed to be refetched; the client must get this metadata from the server.If your schema is large enough it may be a prohibitive amount of metadata.refetch operations will be delayed until this metadata is fetched.To prefetch this metadata via a GraphQL introspection query, do:

importclientfrom'./wherever/you/create/your/apollo/client'importrefetchfrom'apollo-magic-refetch'// initiate the prefetchrefetch.fetchTypeMetadata(client)

If your server forbids client introspection queries, you will have to fetch themetadata by other means. For instance, you could execute the required introspectionquery on the server, and serve the result on a custom REST route:

import{execute}from'graphql'importschemafrom'./path/to/your/graphql/schema'importexpressfrom'express'import{typesQuery}from'apollo-magic-refetch'constapp=express()consttypeMetadataPromise=execute(schema,typesQuery)app.get('/graphql/refetchTypeMetadata',(req,res)=>{typeMetadataPromise.then((data)=>res.json(data))})

And then pass this data torefetch.setTypeMetadatabefore you ever callrefetch():

importrefetchfrom'apollo-magic-refetch'// accepts a promise that resolves to the graphql execution result.refetch.setTypeMetadata(fetch('/graphql/refetchTypeMetadata').then((res)=>res.json()))

Handling Deletions

Typically you callrefetch within theupdate callback of yourMutationthat deletes objects. You just have to callrefetch with the__typenamethat was deleted (in this case,Device) and theid of the deleted object.This refetches any active queries that contain the deleted object in cached data.

For mutations that delete multiple things at once, you may pass an array orSetof ids torefetch, or make multiple calls torefetch in yourupdate method.

import*asReactfrom'react'importgqlfrom'graphql-tag'importrefetchfrom'apollo-magic-refetch'import{Mutation,ApolloConsumer}from'react-apollo'constmutation=gql`mutation destroyDevice($deviceId: Int!) {  destroyDevice(deviceId: $deviceId)}`constDestroyDeviceButton=({deviceId})=>(<ApolloConsumer>{client=>(<Mutationmutation={mutation}update={()=>refetch(client,'Device',deviceId)}/>{destroyDevice=>(<buttononClick={destroyDevice({variables:{deviceId}})})}      </Mutation>    )}</ApolloConsumer>)

Handling Creation

Typically you callrefetch within theupdate callback of yourMutationthat creates objects. You just have to callrefetch with the__typenamethat was created.

Unlike deletions, you don't pass theid of the createdobject. Without a specificid to search for, it simply refetches all activequeries that contain any object of the requested__typename in their cacheddata, in case the created object belongs in the new results. This is lessefficient than refetching queries containing a specificid, but far easierthan manually inserting the created object into each relevant query.

In this example, the__typename of the object being created isDevice.

import*asReactfrom'react'importgqlfrom'graphql-tag'importrefetchfrom'apollo-magic-refetch'import{Mutation,ApolloConsumer}from'react-apollo'importCreateDeviceFormfrom'./CreateDeviceForm'constmutation=gql`mutation createDevice($values: CreateDevice!) {  createDevice(values: $values) {    id  }}`constCreateDeviceFormContainer=()=>(<ApolloConsumer>{client=>(<Mutationmutation={mutation}update={()=>refetch(client,'Device')}/>{createDevice=>(<CreateDeviceFormonSubmit={(values)=>createDevice({variables:{values}})}/>)}</Mutation>)}  </ApolloConsumer>)

Handling associations being broken

In this example, a view shows a list ofOrganizations, each containing asublist ofUsers. When one or more users is removed from an organization,it makes the following call:

refetch(client,[['User',userIds],['Organization',organizationId],])

Passing an array torefetch means to only refetch queries containing all ofthe conditions in the array. So the query below would be refetched, but a querycontaining onlyOrganizations or a query containing onlyUsers would not.

import*asReactfrom'react'importgqlfrom'graphql-tag'importrefetchfrom'apollo-magic-refetch'import{Mutation,ApolloConsumer}from'react-apollo'importOrganizationViewfrom'./OrganizationView'constquery=gql`query {  Organizations {    id    name    Users {      id      username    }  }}`constmutation=gql`mutation removeUsersFromOrganization($organizationId: Int!, $userIds: [Int!]!) {  result: removeUsersFromOrganization(organizationId: $organizationId, userIds: $userIds) {    organizationId    userIds  }}`constOrganizationViewContainer=({organization:{id, name, Users}})=>(<ApolloConsumer>{client=>(<Mutationmutation={mutation}update={(cache,{data:{result:{organizationId, userIds}}})=>refetch(client,[['User',userIds],['Organization',organizationId],])}>{removeUsersFromOrganization=>(<OrganizationVieworganization={organization}onRemoveUsers={userIds=>removeUsersFromOrganization({variables:{organizationId, userIds},})}/>)}</Mutation>)}</ApolloConsumer>)constOrganizationsViewContainer=()=>(<Queryquery={query}>{({data})=>{const{Organizations}=data||{}if(!Organizations)return<div/>return(<div><h1>Organizations</h1>{Organizations.map((organization)=>(<OrganizationViewContainerkey={organization.id}organization={organization}/>)}</div>)}}</Query>)

Handling associations being created

Assuming the sameOrganizations/Users schema as above, the example performsthe necessary refetches when a user is created and added to an organization:

refetch(client,[['User'],['Organization',organizationId]])

In this case noids are given forUser, so any query containing the anOrganization with the givenorganizationId in its results and selecting anyUsers would be refetched. (This doesn't perfectly exclude cases that fetchUsers and Organizations separately, instead of one nested inside the other, butit's better than nothing).

import*asReactfrom'react'importgqlfrom'graphql-tag'importrefetchfrom'apollo-magic-refetch'import{Mutation,ApolloConsumer}from'react-apollo'importCreateUserFormfrom'./CreateUserForm'constmutation=gql`  mutation createUser($organizationId: Int!, $values: CreateUser!) {    result: createUser(organizationId: $organizationId, values: $values) {      organizationId      id      username    }  }`constCreateUserFormContainer=({ organizationId})=>(<ApolloConsumer>{(client)=>(<Mutationmutation={mutation}update={()=>refetch(client,[['User'],['Organization',organizationId]])}>{(createUser)=>(<CreateUserFormonSubmit={(values)=>createUser({variables:{ organizationId, values},})}/>)}</Mutation>)}</ApolloConsumer>)

API

refetch(client, typenameOrTerms, [predicate, [idField]])

importrefetchfrom'apollo-magic-refetch'

Scans active queries in the givenApolloClient and refetches any that containdata matching the given type(s)/id(s).

Arguments

client: ApolloClient

TheApolloClient in which to scan active queries.

typenameOrTerms: string | Array<Term>

The__typename of the GraphQL type that was created or deleted, or an array of[typename, predicate, idField] tuples (predicate andidField are optional). If anarray is given, a query must match all of the conditions in the array to berefetched.

predicate: any (optional)

A single id, an array of ids, or aSet of ids that were deleted, or apredicate function that takes an instance of the GraphQL type and returnstrueif the query should be refetched. If given, only active queries whose currentresult matches the predicate or contains an object with the giventypename andid will be refetched.

idField: string (optional, default:'id')

The name of the id field in the type that was deleted. This is only used ifpredicate is not an id, array, orSet of ids, rather than afunction.

refetch.fetchTypeMetadata(client)

Prefetches type metadata by running an introspection query on the given onApolloClient. The server must support client introspection queries;otherwise userefetch.setTypeMetadata.

Arguments

client: ApolloClient

The client to fetch type metadata from.

refetch.setTypeMetadata(typeMetadataPromise)

Sets the type metadata to use for determing which queries to refetch.Use this method if your server forbids client introspection queries.

Arguments

typeMetadataPromise: TypeMetadata | Promise<TypeMetadata>

The result of executing thetypesQuery GraphQL queryor aPromise that will resolve to the result.

typesQuery

import{typesQuery}from'apollo-magic-refetch'

The parsed GraphQL introspection query that gets all of the type metadataneeded to determine which queries to refetch. Use this if your server forbidsclient introspection queries; execute this query on the server side and sendthe result to the client code that callsrefetch.setTypeMetadata.

About

magically refetches relevant apollo graphql queries after creates, deletes, and association changes

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors4

  •  
  •  
  •  
  •  

[8]ページ先頭

©2009-2025 Movatter.jp