relay: "Uncaught TypeError: Cannot read property 'identifier' of undefined" when calling `retain()` in Relay 8.0.0
This is in an example 1:1 from the official documentation https://relay.dev/docs/en/local-state-management
commitLocalUpdate(modernEnvironment, store => {
const dataID = 'client:store';
const record = store.create(dataID, 'Store');
modernEnvironment.retain({
dataID,
variables: {},
node: {selections: []},
});
});
that causes the following error:
Uncaught TypeError: Cannot read property 'identifier' of undefined
at RelayModernStore.retain (RelayModernStore.js:158)
at RelayModernEnvironment.retain (RelayModernEnvironment.js:223)
I did a bare bones setup based on relay-examples
todo app. Nothing fancy.
Not sure if related: https://github.com/facebook/relay/issues/2971
About this issue
- Original URL
- State: open
- Created 4 years ago
- Reactions: 2
- Comments: 21 (14 by maintainers)
Thank you @jstejada! This works for me for now:
hey @cvle, unfortunately yes. The previous api was also only meant to be used on operations and this formalized it a bit more. I /think/ (but could be wrong) that because we use Flow internally that function wasn’t being type checked externally, and it’s an internal-ish api that isn’t well documented, so people figured out how to handcraft an input that would allow retaining a single record.
That being said, technically you could also handcraft an operationdescriptor to pass to retain without actually creating a query if you really need to, but that would not be the recommended way to use the api.
In any case, i think retaining individual records is probably a valid use case for managing local data, so we’ll consider adding a variant of this api for that use case.
thanks!
Could you update the docs to reflect how to use it to initialize a local store as the docs are very unclear on what to do. Thanks!
@jstejada thanks for the clarifications. I’ll try to describe the issue a bit better.
I have a
selected
, client extended, boolean field on theDocument
type. This field indicates if a given document is selected in a list view.This is all great, until you navigate away from the list view and all React imposed retentions are released because elements (hooks/components) referencing the
selected
field are unmounted.To avoid this loss of state, I want to retain the
selected
field on specific selected documents. This is exactly what I am trying in the code examples.retainedDocuments
mapretainedDocuments
map and dispose of the retention lock because I don’t care about it anymoreI hope this clarifies stuff from my side.
I am back with revelations. Thanks to help from @josephsavona, I’ve figured out a generic way to solve my problem in the above comment.
Relay offers
missingFieldHandlers
which allows it to populate/inject fields which are seemingly missing from the record store.Empowering this feature, we can write type-safe retention requests for records which don’t exist on the root.
Following the Relay GraphQL Server Specification, we know for a fact that when the user requests something like this:
we want a node/record with the globally unique ID behind the
id
argument. The following missing field handler allows such queries to get resolved:Refactoring the original
document.js
from the above comment like this:cleanly implements the wanted behaviour with all Relay benefits!
This
to this?
I’ve figured adding
request: {identifier: 0}
as a sibling ofroot
would make it work, but this looks really hacky. What is the proper way of dealing with this and why are the docs not updated 😞can you just change like this
environment.retain(operation.root)
toevironment.retain(operation)
I think it is related to this commit https://github.com/facebook/relay/commit/1ce3e474a59095773a9e28bd30ae5e2dc32203f0