Skip to content

Instantly share code, notes, and snippets.

@shlomitc
Last active April 2, 2019 14:19
Show Gist options
  • Save shlomitc/86ca1368bee27fe900f4c0ae0599afb3 to your computer and use it in GitHub Desktop.
Save shlomitc/86ca1368bee27fe900f4c0ae0599afb3 to your computer and use it in GitHub Desktop.
Components APIs - Composition vs. Wrapping

Components APIs - Composition vs. Wrapping

The Task:

Create a preview component for social links:

image

The component should be created on top of existing components in the library. Consider the following components:

  1. Text - represnets text in different combinations
  2. ImageViewer - an image picker with additional info

The issues

  1. What APIs should the component have in order to make it consistent, easy to use and to test
  2. The ImageViewer component has rounded corners and fixed size. Should be 100% width/height and with squared corners. This is a requirement only for SocialPreview and not for ImageViewer.

The Approaches:

Approach 1 - CSS composition

const SocialPreview = ({children}) => (
  <div className={styles.socialPreviewComposition}>
    {children}
  </div>
);


const App = () => (
  <SocialPreview>
    <ImageViewer imageUrl="http://wix.com/image.png”/>
    <Text>Preview Url</Text>
    <Text>Title</Text>
    <Text>Description</Text>  
  </SocialPreview>
);

Pros:

  1. Straightforward API
  2. Easy to test each part with it’s own drivers

Cons:

  1. Prone to composition mistakes (since not closed in the component)
  2. Harder to document

Magic:

  1. ImageViewer needs to be configured no to have borders, so the css can apply styles on it with css, or it can be added to the ImageViewer directly

Approach 2 - pass imageViewerProps and propagte to ImageViewer

<SocialPreview
  previewUrl="www.site-name.com"
  title="Site Name | a title of you site"
  description="A short description for a site"
  imageViewerProps={{
    imageUrl: 'https://wix.com/image.png’,
  }}
/>

Pros:

  1. Straightforward
  2. Protected from making mistakes

Cons:

  1. Harder to test the image component
  2. Couples the component directly to ImageViewer, so refactors are harder. Internal implementation becomes public.

Approach 3 - pass <ImageViewer/> as a prop

<SocialPreview
  previewUrl="www.site-name.com"
  title="Site Name | a title of you site"
  description="A short description for a site"
  media={
    <ImageViewer imageUrl="https://wix.com/image.png"/> 
  }
/>

Pros:

  1. 1/2 Straightforward
  2. 1/2 Protected from making mistakes
  3. Testing is easier since data-hook can be applied directly

Cons:

  1. Harder to test the image component

Magic:

  1. Css can be done either internally, but it’s a wild guess, or it needs to be supplied to the ImageViewer

Pros and Cons

Criteria Approach 1 Approach 2 Approach 3
Straightforward API V X X
Test drivers simplicity V X V
Mistake-free (wrong configuration) X V X
Easy to document V V X
Configuring ImageViewer correctly X V X
@hepiyellow
Copy link

Approach 3.b - Generic MediaCard Layout (Composition)

import {SocialPreview} from 'wix-style-react/SocialPreview';

<SocialPreview
  media={<ImageViewer imageUrl="https://wix.com/image.png"/>}
  preTitle="<Text>www.site-name.com<Text/>"
  title="<Text>Site Name | a title of you site</Text>"
  description="<Text>A short description for a site<Text/>"
/>

Render Slots

  • We allow anything to be rendered into the render slots
  • SocialPreview would have style overrides for <Text/> and <ImageViewer/>
    • Styling can be overridden with stylable
  • We can apply default props (By cloning) for <Text/> and <ImageViewer/>
  • We should not do any overriding (only default) of props for <Text/> and <ImageViewer/>
  • Testing is done totally by the consumer, we provide only render slot getter: getMedia(), getTitle(), etc.. which return a HTML Element (of the first child of the slot)

@shlomitc
Copy link
Author

shlomitc commented Apr 2, 2019

this is like approach 1 - only with props and not just children.

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