Kevin He
Kevin He

Reputation: 911

Why redux suggests to only connect to top level components?

I'm new to redux and react-redux, in the mean time I am trying to make a redux app.

I don't understand the statement on redux document:

Then, we wrap the components we want to connect to Redux with the connect() function from react-redux. Try to only do this for a top-level component, or route handlers. While technically you can connect() any component in your app to Redux store, avoid doing this too deeply, because it will make the data flow harder to trace.

Isn't it easier to connect to all components and when state is updated, every component can get the new state tree?

Why dumb components and high level containers?

Thanks.

Upvotes: 23

Views: 7346

Answers (5)

Jules
Jules

Reputation: 1747

Reading the latest answers as of when I post my answer here, I'd like to further add to the consensus of having each component connected using the official Redux style guide:

Prefer having more UI components subscribed to the Redux store and reading data at a more granular level. This typically leads to better UI performance, as fewer components will need to render when a given piece of state changes.

For example, rather than just connecting a <UserList> component and reading the entire array of users, have <UserList> retrieve a list of all user IDs, render list items as <UserListItem userId={userId}>, and have <UserListItem> be connected and extract its own user entry from the store.

This applies for both the React-Redux connect() API and the useSelector() hook.

Upvotes: 1

Brandon
Brandon

Reputation: 7966

As mentioned, Abramov (Redux author) has walked-back his advice re: connect()ed components. He articulates a nice rule of thumb in this Reddit post on the topic:

I do it this way:

  1. Start by using one container and several presentational components

  2. As presentational component tree grows, “middle” components start to pass too many props down

  3. At this point, I wrap some leaf components into containers so that “middle” components don’t need to accept and pass down props that are completely unrelated to them

  4. Repeat

If you watch the last ten videos from my course on Egghead, this is exactly the approach I demonstrate: https://egghead.io/series/getting-started-with-redux

From my reading, the initial advice on connect() had nothing to do w/ performance and everything to do with modular components & ease-of-reasoning about data flow in larger apps.

In fact, more connect()ed components might be a performance advantage vs. the 1-container-to-rule-them-all top-heavy pattern. Abramov once more:

Both approaches are fine, and having nested connect() components is actually going to give you more performance. The downside is they're slightly more coupled to the application and slightly harder to test, but that may not be a big issue.

Upvotes: 22

hex13
hex13

Reputation: 520

When I had one container at the top, I had efficiency problems because React rerendered all my components during slightest update somewhere in the tree. So I abandoned that approach and made my app against docs, which turned out to be faster.

But later I've seen that even Redux author wrote on his Twitter:

Emphasizing “one container component at the top” in Redux examples was a mistake. Don’t take this as a maxim.

https://twitter.com/dan_abramov/status/668585589609005056

and

Try to keep your presentation components separate. Create container components by connecting them when it’s convenient. https://twitter.com/dan_abramov/status/668586001175048192

Upvotes: 15

Mark McKelvy
Mark McKelvy

Reputation: 3536

The answer is in this section from your excerpt of the docs:

While technically you can connect() any component in your app to Redux store, avoid doing this too deeply, because it will make the data flow harder to trace.

One of the core principles of Redux is data should generally flow from the top down, i.e. it should be unidirectional. If you connect too many lower level components, your data flow is no longer unidirectional. The main consequence of this is that it is much easier to have inconsistent state among your components.

When going top-down, which is what naturally happens when you only connect a limited number of high level components, it is much harder to create situations where you have inconsistent state, hence the advice in the docs.

Upvotes: 4

Mike
Mike

Reputation: 1452

In some cases, you can use connect()ed components deeper down. I wouldn't interpret the documentation so strictly.

Generally speaking, if you find yourself passing down too many props from your components and the components doing the passing aren't using those props, then they can be moved to a separate container component.

If you find yourself constantly writing props down a component chain it might be time to add a container:

// A blog post view component
render () {
  const {post} = this.props;

  return (
    <div>
      <h1>{post.title}</h1>

      <Author author={this.props.author}
        onClick={this.props.favAuthor}
        onHover={this.props.authorDetails}
        isAuthorFaved={this.props.isAuthorFaved}
        isAuthorFollowed={this.props.isAuthorFollowed}/>
    </div>
  )
}

In this case, the post component doesn't have any use or need of any props used for <Author/>. You might want to consider making an <AuthorContainer author={this.props.author}/> instead. The author belongs to the post, so you will need that bit of information. The rest can be computed using state in the container's mapStateToProps(state, ownProps) function where ownProps.author is the author object.

Again, this is a contrived example, but it is really up to you in the end where the logic belongs.

Upvotes: 0

Related Questions