📝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. (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 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