I'm building an email inbox using Redux. One half of the screen has a list of email subjects, and you can click one to view the full email contents on the other half of the screen. Most devs would call this a "master-detail" type application.
An email that is displayed in the "master" list (it's a class in my app called SimpleEmail) looks like this. The model has been shrunken down to reduce the amount of data transmitted when fetching a list of possibly 100+ emails.
{
from: "hello@site.com",
subject: "Hello, Jon",
id: "abc123"
}
An email in the "detail" list (a class called EmailDetails) has a model that is way more complicated and has a different shape.
{
id: "abc123"
headers: {
from: "hello@site.com",
subject: "Hello, Jon",
to: [],
bcc: null,
cc: null,
replyTo: // and about 10 more fields
},
bodyHtml: "This is some text",
attachments: [],
receivedAt: null,
// and about 10 other fields
}
How should I shape my application state in redux to handle these two different models being used? My initial thought is to do the following:
{
emailMaster: {
entitiesById: {}, // a Map of emails keyed by ID
ids: [],
selectedId: null
isFetching: false,
isError: false
},
emailDetails: {
selectedEntity: {}, // A single email object
isFetching: false,
isError: false
}
}
I can already see a couple issues with my design:
- The data is not normalized, and thus, there is duplicate data. This violates a major design principle of redux.
- If a user updates an email (such as marking it as unread), I will have to check to see if that email is loaded in the "detail" view, and update the second model. This seems like a code smell.
- There is no single source of truth for which email ID is selected. What if there is a race condition (maybe the user is clicking around the screen really fast) and
emailMaster.selectedIdis a different value fromemailDetails.selectedEntity.id? Again, this seems like a code smell.
Something obviously doesn't feel right. Is there a better way I could go about designing the shape of my application state?