I believe most people are in agreement that using container components is a good practice - described in this popular post: https://medium.com/@learnreact/container-components-c0e67432e005#.qhw8yfodx
I bought into it, however, I think I was doing so a bit too strictly.
One comment in that article mentions that not using container components hinders reusability of those components:
CommentList can’t be reused unless under the exact same circumstances.
While reusability is great, there will always be some components that are not meant to be reused, they have a very specific job that is unique to a certain aspect of your app. So if I don't plan on reusing this component, is there any harm to fetching the data from within the component that renders it?
Use Case:
I've only found myself in this situation because I'm dynamically generating a handful of components that share certain behavior (eg saving user changes to inputs in the component), but otherwise require different store data. So I render my components via a loop with with this shared component as a parent, however I don't want to have to pass the store data into every one of these components when only some need it.
Here's the breakdown:
Container Component -> Shared Component -> Unique Components
Where container component right now is fetching all store data, each unique component is generated from a loop within the container component wrapped in the shared component as a parent. With this current setup, I need to pass all data to every component, via the Shared Component, in order for it to make it to my Unique Components
1 Answer 1
So if I don't plan on reusing this component, is there any harm to fetching the data from within the component that renders it?
Software design is about trade-offs. Separating container components from presentational components brings several advantages - separation of concerns, reusability, testability, etc. These advantages are probably too easily overlooked or lost, which is why articles such as the one you linked make such a big deal out of them. But, if pursuing these advantages creates too many disadvantages (of a more complicated or uglier design, more development work, or whatever), it's not "wrong" to compromise on them, as long as you understand the trade-offs you're making.
A couple of additional thoughts on container components in particular:
- If you're using Redux, you can [connect](https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options) components to the store at arbitrary points in your hierarchy. The container-versus-presentational dilemma of having to pass state in from higher-level components becomes a moot point if your lower-level unique components can connect up to the store themselves.
- Dan Abramov, the creator of React Hot Loader and Redux, gave this example in the Redux documentation:
Sometimes it’s hard to tell if some component should be a presentational component or a container. For example, sometimes form and function are really coupled together, such as in case of this tiny component:
AddTodo
is an input field with an "Add" buttonTechnically we could split it into two components but it might be too early at this stage. It’s fine to mix presentation and logic in a component that is very small. As it grows, it will be more obvious how to split it, so we’ll leave it mixed.
If even the creator of Redux says that it's not always a hard-and-fast line, that's saying something.
Even if you decide to blur the line, you should consider ideas to keep the concepts separate as much as possible. For example:
- Your shared component could be separated so that its shared presentational bits are in one component and the rest of the logic is in a container component (that shows the shared presentational component and wires up the unique children).
- Maybe the shared component could take the unique children as React children, so that it doesn't need any unique state logic. React children can be quite flexible, thanks to techniques such as the various React.Children methods, using cloneElement to inject child properties, and keyed fragments.
- Maybe the shared logic can be in a presentational component and a higher-order component adds the logic to inject state for unique children.