Transform entity / normalized response

86 Views Asked by At

I wonder where is a good place to transform a response entity(ies) before it is set in my Redux state.

Example

  • I have a chat_message entity
  • It has a read boolean property sent by the server
  • I need to compute a new unread boolean property = !message.read && message.user_id !== currentUser.id

Questions

  1. Do I compute this new attribute in a getChatMessages selector (reselect)?
  2. Do I compute this new attribute before I set the normalized response in my state? – Hence my question "Transform"
  3. Do I just calculate it in my Component, but this (simple) logic is not shared and duplicated all over the place...
  4. Do I send the unread attribute from the server...

Notes

  • unread attribute example is a simplified example.
  • I don't like solution 1., cause you need to share this logic between selectors anyway. So you might have a isMessageUnread helper function shared by getLastChatMessage, getChatMessages selectors. I also don't like selectors doing too much logic.
  • I would lean towards solution 2. New unread attribute is computed only when receiving response.
  • Solution 3. is my current lazy solution (with experiments here and there but nothing conclusive really)
  • I don't like solution 4., these attributes are more UI-related than backend-related.
  • If using solution 2., I feel like reducers is not a good place to do this tranformations. Might be easy for simple entities, but what about "heavy" transformation (iterating over collections, checking relationships, etc) ? I would prefer to put that new logic outside of: selectors, reducers, and entities. Kinda like a normalizr "plugin" / interceptor / transformer / post-processor...
2

There are 2 best solutions below

0
On BEST ANSWER

Normalizr provides the processStrategy option:

Strategy to use when pre-processing the entity. Use this method to add extra data, defaults, and/or completely change the entity before normalization is complete.

2
On

The solution depends on how the attribute will be used :

  • Is the unread attribute specific to one single component for its render purpose and not used anywhere else. Eg : A notification dot. If yes, then you can use solution 3, as you can localise the usage within the component.

  • If the unread attribute, needs to be shared across components / middlewares, placing the logic in the selector / reducer is the way to go. But if you are placing in the reducer, ask whether unread is required by all components subscribing to chatBox entity. If not then it is better to place it in a selector, that can be invoked only by those components / middlewares that need it. There is a tradeoff of an extra runtime computation but it provides proper separation of concern as this will eventually benifit if there are more such derived attributes in the future.