facebook / facebook/relay

Subsequent queries can cause previous data to appear "missing" due to normalization

Open
#2,237 29 comments 10 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
19k
Forks
1.9k
PR merge metrics
No merged PRs in 30d

Description

I have a fairly common, very reasonable use case that demonstrates what I believe to be a fundamental flaw in the relay cache/store update strategy.

Let's use these simplified types in the scenario:

```graphql
type SomeObject implements Node {
id: ID!
name: String
description: String
}

type SomeWrapper implements Node {
id: ID!
object: SomeObject
}

type Query {
get(id: ID!): SomeWrapper
search(term: String!): [SomeWrapper]
}
```

The important part here is that `SomeWrapper` references `SomeObject`.

In my use case, I have two `QueryRenderer`s: one to fetch search results, and one to fetch all the details of a selected object. They **must be independent queries** for 2 reasons:

1. the details query fetches MUCH more data than would be practical to return on all search results
2. search query should NOT be re-run each time the selected ID changes for the details query

Here's another heavily simplified description in GraphQL (in reality the queries are large, use the `Connection` spec, and are composed of many fragments):

```graphql
query SearchQuery ($term: String!) {
search (term: $term) {
id
object {
id
name
}
}
}

query DetailsQuery ($id: ID!) {
get (id: $id) {
id
object {
id
name
description
}
}
}
```

The important part here is that the `description` field is present in `DetailsQuery` but NOT in `SearchQuery`.

The problem comes when I have details pulled up for a `Wrapper` with ID `aaa`. It looks like this:

```json
{
"id": "aaa",
"object": {
"id": "111",
"name": "Name 1",
"description": "This is a HUGE piece of data."
}
}
```

Now, let's say that I do a search and receive results which contain `Wrapper` with ID `aaa`. It looks like this:

```json
[
{
"id": "aaa",
"object": {
"id": "111",
"name": "Name 1"
}
}
]
```

Nothing has changed, and this is great. However, let's say that `aaa` has changed to reference `Object` with ID `222`:

```json
[
{
"id": "aaa",
"object": {
"id": "222",
"name": "Name 2"
}
}
]
```

This becomes **EXTREMELY** problematic. Because `222` is new to relay, there is no cache for the `description` field, but the results for `DetailsQuery` are updated to reference it anyhow. While having a "description" go missing doesn't sound like a big deal, my real-world case has dozens of fields with nested queries. **Thus, receiving this kind of search result essentially makes the entire screen go blank.**

The problem, then, is that relay seems to split the middle between two more predictable updating strategies, where it would either:

1. NOT update the `DetailsQuery` results, since it knows that its cache is incomplete
2. Make a followup query to the required `node(id: ID!)` query root for the fields it knows are missing

I believe I can acheive the former by using separate environments, but this feels quite dirty.

If I recall correctly, the latter was the behavior in relay classic. Is there any way to restore this in modern?

I would be very interested to learn the reasoning behind the current behavior, and am willing to helping implement a better one if the relay team is open to the idea.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.