Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 19 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save markerikson/ea312b5ee398627ffceb09f89904831f to your computer and use it in GitHub Desktop.
Save markerikson/ea312b5ee398627ffceb09f89904831f to your computer and use it in GitHub Desktop.
Redux container/presentational structuring

[8:27 PM] cquill: @acemarke Right, so many portions of the UI will be connected. But does each connected portion typically get its own container component? Seems verbose and redundant to have the following for each CRUD resource: UserList, UserListContainer, UserView, UserViewContainer, UserEdit, UserEditContainer, UserNew, UserNewContainer. Is there a simpler way?
[9:56 PM] acemarke: @cquill : this leads into one of my favorite (?) semi-rants, and one that I apparently need to write down so I can paste it
[9:57 PM] acemarke: A "container" component is simply any component whose primary job is to fetch data from somewhere, and pass that data on to its children
[9:58 PM] acemarke: With Redux, the wrapper components generated by connect are "container" components, since their job is to extract data from the Redux store
[9:58 PM] acemarke: I generally dislike the somewhat-common approach of trying to divide everything into a "components" folder and a "containers" folder
[9:59 PM] acemarke: at least when that's done to keep separation between the presentational components and the use of connect
[10:00 PM] acemarke: granted, my actual hands-on experience is a bit limited, but my take is that you generally have "app-specific components that need to be connected to Redux", and "truly generic components that probably aren't going to get connected, or if they are, will be connected many times for different parts of the app"
[10:00 PM] acemarke: so if you're trying to structure things as, say, components/UserList/UserList.jsx, and containers/UserListContainer/UserListContainer.jsx, that's overkill
[10:01 PM] acemarke: just put both of them in one file, export class UserList, and export default connect(mapState)(UserList)
[11:20 PM] CelloG: I find that separating containers and components into different files is good if there is complexity. And I have re-used presentation components with different containers, so it depends on context, as always
[11:21 PM] acemarke: right - if a presentational component is going to get connected multiple ways, or if it's truly generic, then it makes sense to separate it out some
[11:22 PM] acemarke: but, the majority of what I've seen is that most connected components are app-specific, and not connected more than once
[11:22 PM] acemarke: here's a good example of a typical connected component file for me: https://github.com/markerikson/project-minimek/blob/master/src/features/pilots/PilotsList/PilotsListRow.jsx
markerikson/project-minimek
project-minimek - A sample app to demonstrate various useful Redux techniques, accompanying the blog series at http://blog.isquaredsoftware.com/series/practical-redux
[11:23 PM] acemarke: so yeah, as always, YMMV, and that's just my opinion, but I do think that trying to separate all "components" and "containers" just for the sake of keeping them separate is a waste of effort
[11:24 PM] acemarke: especially when you do more work and realize that you actually do need to connect a given component

[10:36 PM] acemarke: okay, so: it helps to understand that the phrase "container component" is just a descriptive term
[10:37 PM] acemarke: that can be applied to any component whose primary job is to fetch data from somewhere, and pass that data to its children
[10:37 PM] don: right
[10:37 PM] acemarke: this could involve making AJAX calls and calling this.setState({theData}), subscribing to a Flux store, or something else
[10:38 PM] acemarke: in the case of Redux, the wrapper components generated by connect() are "container components"
[10:38 PM] acemarke: because all they do is subscribe to the Redux store, extract the requested data, and pass that down to the wrapped component
[10:38 PM] acemarke: now, those wrapped component could themselves be doing additional data fetching or something
[10:38 PM] acemarke: and also be labeled as "containers" if that term is appropriate
[10:39 PM] acemarke: that said, in a typical React+Redux app, the wrapped components generally are not doing data fetching themselves
[10:39 PM] acemarke: they might call this.props.someFunctionThatFetchesData()
[10:39 PM] acemarke: but that function usually goes off and does the fetching and then dispatches the Redux action to store it
[10:39 PM] acemarke: so the component itself isn't actually doing the "container"-type work
[10:39 PM] acemarke: it's just calling whatever function it was given as a prop
[10:40 PM] acemarke: so, as a general observation, most Redux-connected components would be mostly "presentational"
[10:40 PM] BTM: I just generally think of connect() and the intermediate component that it generates under-the-hood as the container.

@swyxio
Copy link

swyxio commented Dec 11, 2018

i think this would be a very good blogpost because most people organize code like this

@markerikson
Copy link
Author

I originally wrote some thoughts on folder structure 2 years ago, in Practical Redux Part 4: UI Layout and Project Structure.

I still use something close to that, although I don't generally bother writing index.js files to "re-export" things.

Code structure is absolutely something I want to address in the upcoming docs content rewrite.

@micnguyen
Copy link

Having stumbled onto this hot on the heels of Redux Toolkit, I think it's important to re-address the importance of presentational/container pattern (or rather, de-emphasize it)

Where the redux docs have a whole section on that idea of separation: https://redux.js.org/basics/usage-with-react#designing-other-components the RTK intermediate tutorial combines them: https://redux-toolkit.js.org/tutorials/intermediate-tutorial which may be confusing to users to are looking at both docs side by side. It would be good for RTK, which is promoting an opinionated approach, to decide on a de-facto pattern.

I personally agree with you @markerikson in that the separation for the sake of separation is unnecessary. Having an entire folder structure that relies on components having an accompanying container is a little too much. In my experience a component that has an accompanying container is rarely used as a generic, bare component elsewhere. About the only tangible benefit in the separation is easier testing so you can do it without a mocked store.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment