📝Injecting container implementation per container

prev
Injecting smart components / containers

Example in Injecting smart components / containers kind of breaks encapsulation because ProfilePage now needs to know that UserPostsContainer and UserFriendsContainer are smart components.

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>
  );
};

Yes, it’s obvious from their names but should it be?

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 simpler
  • ProfilePage is agnostic to whether UserPosts / 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 and UserFriends 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)

Backlinks

Want to receive my 🖋 posts as I publish them?