Skip to content

Documentation request: Working with normalized data in React+Redux, "denormalizing" data best practices #779

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
johot opened this issue Sep 10, 2017 · 8 comments

Comments

@johot
Copy link

johot commented Sep 10, 2017

The documentation for redux and redux+react is really really great but I am really missing one thing that has confused me for a while.

When working with a flat/normalized state shape it's a bit unclear for me when the best time is to "denormalize" the data, that is lookup the real data/entities so I can pass it to my component or it's child components.

Let's make an example, we have built a book recommendation app/webpage.

const state = {

    bookLists: {
        0: {
            title: "Great fantasy books",
            books: [0, 1]
        },
        1: {
            title: "Best Sci-Fi of the year",
            books: [2]
        }
    }
    books: {
        0: {
            author: "J.R.R Tolkien",
            title: "Lord of the rings"
        },
        // And so on...
    }
}

Now let's imagine we want to render all book lists and their corresponding books on the same page. Our component hierarchy would probably be something like:

<BookPage>
    <BookList>
        <Book />
        <Book />
        <Book />
   </BookList>
   <BookList>
        <Book />
        <Book />
        <Book />
    </BookList>
    ...
</BookPage>

Questions + answers I wish we could update the documentation with (or discuss here):

Each book needs to be resolved from the ids of the booklist. Where would this be done? Options I can think of:

  • In the mapStateToProps for the BookList by doing a .map for each book id?
  • By passing the book ids to the child Book components and have them use connect to get the information from the state?
  • Another better option?

Each of the suggested options have some problems:

  • In the first option (mapStateToProps and .map from ids) each BookList will be re-rendered when the state is changed since the mapping between id and book objects would create a new array of books which when passed to a BookList would cause a shallow comparion to fail causing a re-render.

  • Using the second option instead (passing ids to child components) shallow comparison would work better but feels "wrong". Should a component really receive only an id? It feels hard to re-use and test them that way?

How would you handle this? I would love some guidance!

@markerikson
Copy link
Contributor

markerikson commented Sep 10, 2017

Either works, but the second approach is generally better for performance. There's an excellent writeup on the topic at High-Performance Redux, my own blog post on Practical Redux, Part 6: Connected Lists, Forms, and Performance discusses why this is a good idea, and I have a bunch of additional articles on similar topics in the Redux Performance section of my React/Redux links list.

Note that the second approach means the individual connected items really wind up getting the ID and the actual item as props, and thus should only re-render when the actual item object has been updated.

We did have someone who had volunteered to write an "Optimization" page at reduxjs/redux#1783, but that person seems to have disappeared.

@johot
Copy link
Author

johot commented Sep 10, 2017

Thank you @markerikson that sounds great I will read through your posts!

As you said both will work, but the first one has a big problem in the fact that it will re-render so many components. The only way to use that approach and not have a lot of re-renders would probably be to implement your own shouldUpdateComponent()?

As I said it would be really nice to add something about this in the "Usage with React" section of the official redux documentation, or as a follow up to the normalizing state shape documentation. I wonder if @gaearon have any recommendations about this also, couldn't find any through googling :)

About the second option you mean that in the end the presentation component will get the complete object so we "never really" have components that take only a single id? Never thought about that but it makes sense :)

What I would probably do in my own projects is to name components that only take an id ComponentNameContainer to make it obvious that this is a container component that was designed for use with redux. So in the example I would create a component named BookContainer that only accepts a book id wrapping a Book component that would take an entire book object. Something like that is what you meant also right?

Do you also think it would be a good idea to write about this in the documentation? I'm not sure I would even put it in the optimization category since, for me at least, it's even more about best practises and "how to think" when working with normalized data in redux.

@markerikson
Copy link
Contributor

Yeah, for option 1, you'd have to probably need to do some deeper comparisons or something similar.

Dan is mostly hands-off with Redux these days, and I'm the semi-official keeper of the Redux docs. Yes, I'd love to have some docs added about this sort of thing. We were hoping to get that included in the "Optimization" page, but since that effort stalled, it hasn't happened yet. And yeah, it's somewhere between "optimization" and "architectural practice".

I'm afraid I don't have time to tackle adding new docs pages myself atm, but if you'd be interested in contributing something, I'd be very happy to work with you on content, approach, and editing.

@bonusrk
Copy link

bonusrk commented Nov 14, 2017

@markerikson , dear sir, i would like to help you and @johot with this, if you still need some contributions to docs.

@markerikson
Copy link
Contributor

@bonusrk : yes, glad to hear it! Please file an issue in the main Redux repo describing what you want to add, and we can work together to figure out the details.

@bonusrk
Copy link

bonusrk commented Nov 15, 2017

@markerikson maybe there are some higher priority tasks with docs, maybe like some abandoned pr? Or i can take any requested question from redux repo to start with?

@markerikson
Copy link
Contributor

@bonusrk : anything with a "documentation" tag in either repo is available to be worked on.

@OliverJAsh
Copy link
Contributor

@johot

In the first option (mapStateToProps and .map from ids) each BookList will be re-rendered when the state is changed since the mapping between id and book objects would create a new array of books which when passed to a BookList would cause a shallow comparion to fail causing a re-render.

In that scenario, wouldn't the book objects inside the new books array have the same reference? In that case, BookList would pass a shallow equal comparison for the books array prop? Furthermore, Book would receive the same reference book objects as props, so that too would pass a shallow equal comparison for the book object prop.

@timdorr timdorr closed this as completed Apr 20, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants