📝Injecting container implementation per container
Example in Injecting smart components / containers kind of breaks encapsulation because ProfilePage
now needs to know that UserPostsContainer
and UserFriendsContainer
are smart components. (Yes, it’s obvious from their names but should it be?)
This also becomes more tedious when a container component is used in multiple view component (each view component would require its own context).
// ProfilePage view component
import { useContext } from 'react';
import ProfilePageContext from './ProfilePageContext';
export const ProfilePage = ({ name, userId }) => {
const { UserPostsContainer, UserFriendsContainer } = useContext(ProfilePageContext);
return (
<div>
<h1>{name}</h1>
<UserPostsContainer userId={userId} />
<UserFriendsContainer userId={userId} />
</div>
);
};
One of the way to fix that is to wrap all containers in their own context:
export const UserPostsContext = createContext(UserPostsContainer);
export const UserPosts = (props) => {
const Container = useContext(UserPostsContext);
return <Container {...props} />
}
Then ProfilePage
becomes:
// ProfilePage view component
export const ProfilePage = ({ name, userId }) => {
return (
<div>
<h1>{name}</h1>
<UserPosts userId={userId} />
<UserFriends userId={userId} />
</div>
);
};
Pros
ProfilePage
is simplerProfilePage
is agnostic to whetherUserPosts
/UserFriends
are smart or dumb components (you can treat them as dumb)You can transparently change
UserPosts
into a dumb or smart component
Cons
More contexts. You can use default values to avoid context providers in app, but you’ll need more providers for testing
More deeply nested hierarchy. Each container would now have one extra level of nesting.
It is less obvious that
UserPosts
andUserFriends
are smart components. This design increases the chance that a view component would accidentally use a smart component. The first design requires deliberation for every smart component use.Using default values makes it less obvious what containers you need to mock for testing.
Boilerplate for every container (although in first design you needed boilerplate for every view that uses smart components)