UNPKG

relay-runtime

Version:

A core runtime for building GraphQL-driven applications.

735 lines (527 loc) • 18.9 kB
--- id: store title: Store slug: /api-reference/store/ description: API reference for the Relay store keywords: - store --- import DocsRating from '@site/src/core/DocsRating'; import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal'; The Relay Store can be used to programmatically update client-side data inside [`updater` functions](../../guided-tour/updating-data/graphql-mutations/). The following is a reference of the Relay Store interface. Table of Contents: - [RecordSourceSelectorProxy](#recordsourceselectorproxy) - [RecordProxy](#recordproxy) - [RecordSourceProxy](#recordsourceproxy) - [ConnectionHandler](#connectionhandler) ## RecordSourceSelectorProxy The `RecordSourceSelectorProxy` is the type of the `store` that [`updater` functions](../../guided-tour/updating-data/graphql-mutations/) receive as an argument. The following is the `RecordSourceSelectorProxy` interface: ```javascript interface 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<?RecordProxy>; invalidateStore(): void; } ``` ### `create(dataID: string, typeName: string): RecordProxy` Creates a new record in the store given a `dataID` and the `typeName` as defined by the GraphQL schema. Returns a [`RecordProxy`](#recordproxy) which serves as an interface to mutate the newly created record. #### Example ```javascript const record = store.create(dataID, 'Todo'); ``` ### `delete(dataID: string): void` Deletes a record from the store given its `dataID`. For existing edges to the deleted record, `undefined` will be returned in the default case even when the value is typed as non-nullable. When [`@throwOnFieldError`](../../guides/throw-on-field-error-directive/) is present, the missing data will throw an error. #### Example ```javascript store.delete(dataID); ``` ### `get(dataID: string): ?RecordProxy` Retrieves a record from the store given its `dataID`. Returns a [`RecordProxy`](#recordproxy) which serves as an interface to mutate the record. #### Example ```javascript const record = store.get(dataID); ``` ### `getRoot(): RecordProxy` Returns the [`RecordProxy`](#recordproxy) representing the root of the GraphQL document. #### Example Given the GraphQL document: ```graphql viewer { id } ``` Usage: ```javascript // Represents root query const root = store.getRoot(); // Get the viewer linked record const viewer = root.getLinkedRecord('viewer'); ``` ### `getRootField(fieldName: string): ?RecordProxy` Retrieves a root field from the store given the `fieldName`, as defined by the GraphQL document. Returns a [`RecordProxy`](#recordproxy) which serves as an interface to mutate the record. #### Example Given the GraphQL document: ```graphql viewer { id } ``` Usage: ```javascript const viewer = store.getRootField('viewer'); ``` ### `getPluralRootField(fieldName: string): ?Array<?RecordProxy>` Retrieves a root field that represents a collection from the store given the `fieldName`, as defined by the GraphQL document. Returns an array of [`RecordProxies`](#recordproxy). #### Example Given the GraphQL document: ```graphql nodes(first: 10) { # ... } ``` Usage: ```javascript const nodes = store.getPluralRootField('nodes'); ``` ### `invalidateStore(): void` Globally invalidates the Relay store. This will cause any data that was written to the store before invalidation occurred to be considered stale, and will be considered to require refetch the next time a query is checked with `environment.check()`. #### Example ```javascript store.invalidateStore(); ``` After global invalidation, any query that is checked before refetching it will be considered stale: ```javascript environment.check(query) === 'stale' ``` ## RecordProxy The `RecordProxy` serves as an interface to mutate records: ```javascript interface RecordProxy { copyFieldsFrom(sourceRecord: RecordProxy): void; getDataID(): string; getLinkedRecord(name: string, arguments?: ?Object): ?RecordProxy; getLinkedRecords(name: string, arguments?: ?Object): ?Array<?RecordProxy>; getOrCreateLinkedRecord( name: string, typeName: string, arguments?: ?Object, ): RecordProxy; getType(): string; getValue(name: string, arguments?: ?Object): mixed; setLinkedRecord( record: RecordProxy, name: string, arguments?: ?Object, ): RecordProxy; setLinkedRecords( records: Array<?RecordProxy>, name: string, arguments?: ?Object, ): RecordProxy; setValue(value: mixed, name: string, arguments?: ?Object): RecordProxy; invalidateRecord(): void; } ``` ### `getDataID(): string` Returns the `dataID` of the current record. #### Example ```javascript const id = record.getDataID(); ``` ### `getType(): string` Gets the type of the current record, as defined by the GraphQL schema. #### Example ```javascript const type = user.getType(); // User ``` ### `getValue(name: string, arguments?: ?Object): mixed` Gets the value of a field in the current record given the field name. #### Example Given the GraphQL document: ```graphql viewer { id name } ``` Usage: ```javascript const name = viewer.getValue('name'); ``` Optionally, if the field takes arguments, you can pass a bag of `variables`. #### Example Given the GraphQL document: ```graphql viewer { id name(arg: $arg) } ``` Usage: ```javascript const name = viewer.getValue('name', {arg: 'value'}); ``` ### `getLinkedRecord(name: string, arguments?: ?Object): ?RecordProxy` Retrieves a record associated with the current record given the field name, as defined by the GraphQL document. Returns a `RecordProxy`. #### Example Given the GraphQL document: ```graphql rootField { viewer { id name } } ``` Usage: ```javascript const rootField = store.getRootField('rootField'); const viewer = rootField.getLinkedRecord('viewer'); ``` Optionally, if the linked record takes arguments, you can pass a bag of `variables` as well. #### Example Given the GraphQL document: ```graphql rootField { viewer(arg: $arg) { id } } ``` Usage: ```javascript const rootField = store.getRootField('rootField'); const viewer = rootField.getLinkedRecord('viewer', {arg: 'value'}); ``` ### `getLinkedRecords(name: string, arguments?: ?Object): ?Array<?RecordProxy>` Retrieves the set of records associated with the current record given the field name, as defined by the GraphQL document. Returns an array of `RecordProxies`. #### Example Given the GraphQL document: ```graphql rootField { nodes { # ... } } ``` Usage: ```javascript const rootField = store.getRootField('rootField'); const nodes = rootField.getLinkedRecords('nodes'); ``` Optionally, if the linked record takes arguments, you can pass a bag of `variables` as well. #### Example Given the GraphQL document: ```graphql rootField { nodes(first: $count) { # ... } } ``` Usage: ```javascript const rootField = store.getRootField('rootField'); const nodes = rootField.getLinkedRecords('nodes', {count: 10}); ``` ### `getOrCreateLinkedRecord(name: string, typeName: string, arguments?: ?Object)` Retrieves a record associated with the current record given the field name, as defined by the GraphQL document. If the linked record does not exist, it will be created given the type name. Returns a `RecordProxy`. #### Example Given the GraphQL document: ```graphql rootField { viewer { id } } ``` Usage: ```javascript const rootField = store.getRootField('rootField'); const newViewer = rootField.getOrCreateLinkedRecord('viewer', 'User'); // Will create if it doesn't exist ``` Optionally, if the linked record takes arguments, you can pass a bag of `variables` as well. ### `setValue(value: mixed, name: string, arguments?: ?Object): RecordProxy` Mutates the current record by setting a new value on the specified field. Returns the mutated record. Given the GraphQL document: ```graphql viewer { id name } ``` Usage: ```javascript viewer.setValue('New Name', 'name'); ``` Optionally, if the field takes arguments, you can pass a bag of `variables`. ```javascript viewer.setValue('New Name', 'name', {arg: 'value'}); ``` ### `copyFieldsFrom(sourceRecord: RecordProxy): void` Mutates the current record by copying the fields over from the passed in record `sourceRecord`. #### Example ```javascript const record = store.get(id1); const otherRecord = store.get(id2); record.copyFieldsFrom(otherRecord); // Mutates `record` ``` ### `setLinkedRecord(record: RecordProxy, name: string, arguments?: ?Object)` Mutates the current record by setting a new linked record on the given field name. #### Example Given the GraphQL document: ```graphql rootField { viewer { id } } ``` Usage: ```javascript const rootField = store.getRootField('rootField'); const newViewer = store.create(/* ... */); rootField.setLinkedRecord(newViewer, 'viewer'); ``` Optionally, if the linked record takes arguments, you can pass a bag of `variables` as well. ### `setLinkedRecords(records: Array<RecordProxy>, name: string, variables?: ?Object)` Mutates the current record by setting a new set of linked records on the given field name. #### Example Given the GraphQL document: ```graphql rootField { nodes { # ... } } ``` Usage: ```javascript const rootField = store.getRootField('rootField'); const newNode = store.create(/* ... */); const newNodes = [...rootField.getLinkedRecords('nodes'), newNode]; rootField.setLinkedRecords(newNodes, 'nodes'); ``` Optionally, if the linked record takes arguments, you can pass a bag of `variables` as well. ### `invalidateRecord(): void` Invalidates the record. This will cause any query that references this record to be considered stale until the next time it is refetched, and will be considered to require a refetch the next time such a query is checked with `environment.check()`. #### Example ```javascript const record = store.get('4'); record.invalidateRecord(); ``` After invalidating a record, any query that references the invalidated record and that is checked before refetching it will be considered stale: ```javascript environment.check(query) === 'stale' ``` ## RecordSourceProxy The `RecordSourceProxy` serves as an interface to mutate records. :::danger `RecordSourceProxy` exposes many low level APIs that are not typesafe. Users should consider using [typesafe updaters](../../guided-tour/updating-data/typesafe-updaters-faq/), [optimistic updates](../../guided-tour/updating-data/graphql-mutations/#optimistic-updates), and [relay resolvers](../../guides/relay-resolvers/introduction/) instead if their use case can be covered by these alternatives. ::: ```javascript interface RecordSourceProxy { create(dataID: DataID, typeName: string): RecordProxy; delete(dataID: DataID): void; get(dataID: DataID): ?RecordProxy; getRoot(): RecordProxy; invalidateStore(): void; readUpdatableFragment<TFragmentType: FragmentType, TData>( fragment: UpdatableFragment<TFragmentType, TData>, fragmentReference: HasUpdatableSpread<TFragmentType>, ): UpdatableData<TData>; readUpdatableQuery<TVariables: Variables, TData>( query: UpdatableQuery<TVariables, TData>, variables: TVariables, ): UpdatableData<TData>; } ``` ### `create(dataID: DataID, typeName: string): RecordProxy` Creates a new record in the store given a `dataID` and the `typeName` as defined by the GraphQL schema. Returns a [`RecordProxy`](#recordproxy) which serves as an interface to mutate the newly created record. #### Example ```javascript const record = store.create(dataID, 'Todo'); ``` ### `delete(dataID: DataID): void` Deletes a record from the store given its `dataID`. For existing edges to the deleted record, `undefined` will be returned in the default case even when the value is typed as non-nullable. When [`@throwOnFieldError`](../../guides/throw-on-field-error-directive/) is present, the missing data will throw an error. #### Example ```javascript store.delete(dataID); ``` ### `get(dataID: DataID): ?RecordProxy` Retrieves a record from the store given its `dataID`. Returns a [`RecordProxy`](#recordproxy) which serves as an interface to read/mutate the record. #### Example ```javascript const record = store.get(dataID); ``` ### `getRoot(): RecordProxy` Returns the [`RecordProxy`](#recordproxy) representing the root of the GraphQL document. #### Example Given the GraphQL document: ```graphql viewer { id } ``` Usage: ```javascript // Represents root query const root = store.getRoot(); // Get the viewer linked record const viewer = root.getLinkedRecord('viewer'); ``` ### `invalidateStore(): void;` Globally invalidates the Relay store. This will cause any data that was written to the store before invalidation occurred to be considered stale, and will be considered to require refetch the next time a query is checked with `environment.check()` or is fetched with a `store-or-network` [fetch policy](../../guided-tour/reusing-cached-data/fetch-policies/). #### Example ```javascript store.invalidateStore(); ``` After global invalidation, any query that is checked before refetching it will be considered stale: ```javascript environment.check(query) === 'stale' ``` ### `readUpdatableFragment(fragment: UpdatableFragment<TFragmentType, TData>,fragmentReference: HasUpdatableSpread<TFragmentType>): UpdatableData<TData>;` Fetches an updatable fragment from the store. This updatable fragment's fields can then be imperatively modified to update data in the store. For more information on updating the store imperatively, see this [section](../../guided-tour/updating-data/imperatively-modifying-store-data/) of the guided tour. #### Example ```javascript const fragment = graphql` fragment StoryLikeButton_updatable on Story @updatable { likeCount doesViewerLike } `; const { updatableData } = store.readUpdatableFragment( fragment, story ); updatableData.likeCount = updatableData.likeCount + 1 ``` ### `readUpdatableQuery(query: UpdatableQuery<TVariables, TData>,variables: TVariables): UpdatableData<TData>` Reads an updatable query from the store. This updatable query's fields can be imperatively modified to update data in the store. Unlike `readUpdatableFragment`, you do not need to pass in a `fragmentReference` as an input argument. For more information on updating the store imperatively, see this [section](../../guided-tour/updating-data/imperatively-modifying-store-data/) of the guided tour. #### Example ```javascript const {updatableData} = store.readUpdatableQuery( graphql` query NameUpdaterUpdateQuery @updatable { viewer { name } } `, {} ); const viewer = updatableData.viewer; viewer.name = newName; ``` ## ConnectionHandler `ConnectionHandler` is a utility module exposed by `relay-runtime` that aids in the manipulation of connections. `ConnectionHandler` exposes the following interface: ```javascript interface ConnectionHandler { getConnection( record: RecordProxy, key: string, filters?: ?Object, ): ?RecordProxy, createEdge( store: RecordSourceProxy, connection: RecordProxy, node: RecordProxy, edgeType: string, ): RecordProxy, insertEdgeBefore( connection: RecordProxy, newEdge: RecordProxy, cursor?: ?string, ): void, insertEdgeAfter( connection: RecordProxy, newEdge: RecordProxy, cursor?: ?string, ): void, deleteNode(connection: RecordProxy, nodeID: string): void } ``` ### `getConnection(record: RecordProxy, key: string, filters?: ?Object)` Given a record and a connection key, and optionally a set of filters, `getConnection` retrieves a [`RecordProxy`](#recordproxy) that represents a connection that was annotated with a `@connection` directive. First, let's take a look at a plain connection: ```graphql fragment FriendsFragment on User { friends(first: 10) { edges { node { id } } } } ``` Accessing a plain connection field like this is the same as other regular fields: ```javascript // The `friends` connection record can be accessed with: const user = store.get(userID); const friends = user && user.getLinkedRecord('friends'); // Access fields on the connection: const edges = friends && friends.getLinkedRecords('edges'); ``` When using [usePaginationFragment](../use-pagination-fragment/), we usually annotate the actual connection field with `@connection` to tell Relay which part needs to be paginated: ```graphql fragment FriendsFragment on User { friends(first: 10, orderby: "firstname") @connection( key: "FriendsFragment_friends", ) { edges { node { id } } } } ``` For connections like the above, `ConnectionHandler` helps us find the record: ```javascript import {ConnectionHandler} from 'relay-runtime'; // The `friends` connection record can be accessed with: const user = store.get(userID); const friends = ConnectionHandler.getConnection( user, // parent record 'FriendsFragment_friends', // connection key {orderby: 'firstname'} // 'filters' that is used to identify the connection ); // Access fields on the connection: const edges = friends.getLinkedRecords('edges'); ``` ### Edge creation and insertion #### `createEdge(store: RecordSourceProxy, connection: RecordProxy, node: RecordProxy, edgeType: string)` Creates an edge given a [`store`](#recordsourceselectorproxy), a connection, the edge node, and the edge type. #### `insertEdgeBefore(connection: RecordProxy, newEdge: RecordProxy, cursor?: ?string)` Given a connection, inserts the edge at the beginning of the connection, or before the specified `cursor`. #### `insertEdgeAfter(connection: RecordProxy, newEdge: RecordProxy, cursor?: ?string)` Given a connection, inserts the edge at the end of the connection, or after the specified `cursor`. #### Example ```javascript const user = store.get(userID); const friends = ConnectionHandler.getConnection(user, 'FriendsFragment_friends'); const newFriend = store.get(newFriendId); const edge = ConnectionHandler.createEdge(store, friends, newFriend, 'UserEdge'); // No cursor provided, append the edge at the end. ConnectionHandler.insertEdgeAfter(friends, edge); // No cursor provided, insert the edge at the front: ConnectionHandler.insertEdgeBefore(friends, edge); ``` ### `deleteNode(connection: RecordProxy, nodeID: string): void` Given a connection, deletes any edges whose node id matches the given id. #### Example ```javascript const user = store.get(userID); const friends = ConnectionHandler.getConnection(user, 'FriendsFragment_friends'); ConnectionHandler.deleteNode(friends, idToDelete); ``` <DocsRating />