Hey everyone. I’ve been wrestling with how best to approach state management and would like some feedback from the community on best practices. I’ll use an example to illustrate the question.
Suppose I have an application with “posts” that each have an “user” as the author, and I want to list out the posts with user data. A GraphQL query for the data may look like this:
{
posts {
id
body
user {
id
name
}
}
}
And return data like this:
{
"data": {
"posts": [{
"id": "1",
"body": "Hello John",
"user": {
"id": "1",
"name": "Bob"
}
},
{
"id": "2",
"body": "Hi Bob",
"user": {
"id": "2",
"name": "John"
}
},
{
"id": "3",
"body": "What's the latest?",
"user": {
"id": "1",
"name": "Bob"
}
}]
}
}
My initial approach would be to model the state like this:
type alias User =
{ id : String
, name : String
}
type alias Post =
{ id : String
, body : String
, user : User
}
type alias Model =
{ posts : List Post
}
The problem is that user "1"
(Bob) appears twice and his data is now duplicated in two places. Anytime user attributes change, I would need to crawl the model for all the places where duplicates may be stored and update them.
This is along the same lines as what Brian describes here:
It seems like the way to get around this would be to create an “identity map” using a Dict
and just store user IDs on posts:
type alias User =
{ id : String
, name : String
}
type alias Post =
{ id : String
, body : String
, userId : String
}
type alias Model =
{ posts : List Post
, users : Dict String User
}
This seems suboptimal because I am now forced to deal with an "impossible state."
According to my API contract, I can be confident that my query will always return user data for each post (or else it should fail at the JSON decoding layer). However, fetching the user by ID from the Dict
will return a Maybe User
. When I’m iterating over posts to display them in the view, I have to handle
the Nothing
case that will never actually get called.
I’m not sure what is worse:
- Forcing myself handle
Maybe
everywhere I use aDict
identity map, or - Accepting the duplication (thereby making the impossible state impossible) and maintaining a user update function that knows all the places to propagate changes to user state
Or, am I missing some other way to deal with this?
Thanks for your time!
Related: