0

If in my React app, utilizing Redux and redux-thunk, my store has an array of relatively lightweight/denormalized items that is used in a listing of said items (paginated in the API), but then I also have an edit/add option for each (which is the same item as in the listing array but with many additional fields, not de-normalized, etc.), I don't know which of the following is the best approach for storing in my store:

  1. Maintain one array of items in my store, which contains all necessary data (normalized, and therefore each contains a relatively deep object graph). Editing simply requires finding it in the store, making the changes, and slicing back into the state.items array.
  2. Maintain an array of minimalist items for the item listing, while also having a root state.currentItem object.
  3. Maintain an array of minimalist items for the item listing, while resetting the array to contain only one item (containing all necessary data for editing). This avoids needing to create another reducer which may or may not be a good thing.

Because of the data-intensiveness of the actual listing item object, I have to go with option 2/3, but now I've got redundant data in two places that conceivably won't be in sync (although practically speaking, in my app, because of paging/sorting I must necessarily re-poll for latest data from the API upon returning back to the listing) or an array of items that can contain items in two different object formats.

Both feel dirty, which leads me to believe I'm missing something obvious that redux is already equipped to handle. Suggestions? Additional options?

Ted
  • 7,122
  • 9
  • 50
  • 76

1 Answers1

0

Can the user update multiple items at the same time? Redux has 3 important principles to respect. One of them is the single source of truth, which means all valid/true data must come from one place (store here) and every data element is stored exactly once. Having multiple time the same items in the store is bad, mainly because of sync problems like you said. Also having deep objects is not a good approach, you should keep your state flat. Since you're using react with redux, you have access to state, the app state with redux and the component state with react. The most common pattern with this kind of problem is to create a copy of the object that you are editing in the component state. If the user cancels the editing, it will be easy to revert it. If the user stops editing the item without saving, you app state won't be affected. Also, you will avoid polluting your app state with wrong or duplicated data. Let's say that in your list when a user clicks on an item, the item transform to a text input. The list item will be base on the redux store item and the text input will be base on a copy of the same item. This also applies to new objects. You can also validate your item before adding/updating it. Keep in mind that the most important part is to keep your store clean because you will base you displayed items on that, so fetching new items won't affect your list. Doing this will also help you updating the item in the store because you will only have to replace it when dispatching a save action.

Vincent D'amour
  • 3,746
  • 1
  • 27
  • 39
  • Thanks for your response. Much of what you refer to I'm aware of, but I'm still left in a quandary: I can't store a deep graph of 10,000+ items at the root (in turn containing exponentially more when factoring in all the related data), but I need to have a single source of truth. At this point, I guess I deal with this by get the paginated listing with minimal data for the listing. Then when off to edit, replace that array with a new array of one with the deep graph with all data necessary for all properties as the single entry. All lookup lists for multiple items go to the root of the store. – Ted Mar 16 '17 at 17:34
  • Still feel like it's not right and I'm missing the obvious, but at least then I've got a single source of truth. – Ted Mar 16 '17 at 17:35
  • Oh, and in this particular scenario, no, can't edit more than one at a time. With other objects, yes, but object graph is much simpler so no quandary on how to deal with. – Ted Mar 16 '17 at 17:37
  • Do you need all of those 10,000 items front-end? Or big are those items (of many props)? Are all of those items flat? Is there duplicated data? Having 10,000 items might be the problem. Can you compute some data before sending them, are maybe even compute the component? If your items are flat and small there is no problem having 10,000+ items stored in memory, as long as they are not all rendered. – Vincent D'amour Mar 16 '17 at 19:46
  • No, but it emphasizes my issue: I'm dealing with large numbers and deep object graphs. I page the 10k items, so never going to have all of them in the store, but with a deep object graph, it's difficult to see how to normalize data without duplicating data. – Ted Mar 16 '17 at 23:38
  • I guess the guiding recommendation is from http://redux.js.org/docs/faq/OrganizingState.html#organizing-state-nested-data. "Data with IDs, nesting, or relationships should generally be stored in a “normalized” fashion: each object should be stored once, keyed by ID, and other objects that reference it should only store the ID rather than a copy of the entire object. It may help to think of parts of your store as a database, with individual “tables” per item type. Libraries such as normalizr and redux-orm can provide help and abstractions in managing normalized data." – Ted Mar 16 '17 at 23:39
  • Yes, I would greatly recommend using normalizr and store items by key. Having all data normalized will avoid any form of duplication fo sure. – Vincent D'amour Mar 17 '17 at 00:04
  • 1
    A much better description of the problem and possible solutions can be found in the original discussion Dan Abramov (the creator of normalizr) had ran into the same issues way back when: https://groups.google.com/forum/#!topic/reactjs/jbh50-GJxpg – Ted Mar 17 '17 at 00:09
  • ...and, should note, the creator of redux, and usually the answer to any question involving redux, normalizr, react, etc. ;-) – Ted May 08 '17 at 17:10