4 May 2017

Componentization

  • Vanilla JS
  • Vue
  • React

In programs like Sketch, we keep things DRY (“don’t repeat yourself”) by turning our design decisions into “symbols.” It’s no different in front-end land, so this play will introduce you to a few different ways of encapsulating your designs as “components.”

Scenario

Let’s suppose you’re designing an activity feed for a social networking application. You’ve designed a “card” in Sketch that represents a single item in the feed, but you want to verify that your design works at scale, given a sample set of data.

Rundown

You’ve figured out that the following chunk of markup produces a single, beautiful, “card.”

<div class="bg-white ba b--black-10 pa3">
  <div class="flex">
    <img class="mr2" src="..." alt="" />
    <div>
      <h1 class="f6 mv0 blue">Paul Smith</h1>
      <ul class="mb0 mt1 pl0 list f6">
        <li class="dib black-50">3 mins</li>
      </ul>
    </div>
  </div>
  <p class="f3 fw3 mt3 mb0">
    What a time to be alive! So many front-end resources,
    so little time...
  </p>
</div>

Mockup

The Final Product

Having read the play on tabular data, you’ve also identified a schema to represent your activity feed.

let posts = [
  {
    name: "Paul Smith",
    timeago: "3 mins",
    avatar: "http://placehold.it/50x50",
    status: "What a time to be alive! So many front-end resources..."
  },
  {
    name: "Jane Doe",
    timeago: "1 hour",
    avatar: "http://placehold.it/50x50",
    status: "Does anyone actually use Facebook stories?"
  },
  {
    name: "Alex Jackson",
    timeago: "2 hours",
    avatar: "http://placehold.it/50x50",
    status: "Best slice of pizza in NYC? Go."
  }
];

With our schema in place, let’s get to the implementations.


Implementation — Vanilla JS (ES6)

Here’s the game plan:

  • Write a function that takes a post object and returns a chunk of markup with the name, timeago, avatar, and status properties interpolated accordingly.
function post_markup(post) {
  return `
  <div class="bg-white ba b--black-10 pa3 mb3">
    <div class="flex">
      <img class="mr2" src="${post.avatar}" alt="" />
      <div>
        <h1 class="f6 mv0 blue">${post.name}</h1>
        <ul class="mb0 mt1 pl0 list f6">
          <li class="dib black-50">${post.timeago}</li>
        </ul>
      </div>
    </div>
    <p class="f3 fw3 mv3">${post.status}</p>
  </div>
`
}
  • Iterate over the array of posts using forEach1
  • For each post, call the post_markup function and insert the return value into the DOM
posts.forEach(post => {
  let postElement = post_markup(post)
  stage.insertAdjacentHTML("beforeend", postElement);
});

See the Pen Componentization - Vanilla JS (ES6) by Matt Rothenberg (@mattrothenberg) on CodePen.

Implementation — Vue JS

Here’s the game plan:

  • Construct a Vue instance, passing our array of posts to its data attribute
new Vue({
  el: "#app", // DOM element that wraps our list
  data: {
    posts: posts // our posts array from earlier
  }
});
  • Define a Post component that takes a post object as its sole property and renders our post markup accordingly
Vue.component("Post", { // so we can access it in our markup
  props: ["post"], // each post component gets a post :)
  template: `
    <div class="bg-white ba b--black-10 pa3 mb3">
      <div class="flex">
        <img class="mr2" :src="post.avatar" alt="" />
        <div>
          <h1 class="f6 mv0 blue"></h1>
          <ul class="mb0 mt1 pl0 list f6">
            <li class="dib black-50"></li>
          </ul>
        </div>
      </div>
      <p class="f3 fw3 mv3">
        
      </p>
    </div>
  ` // please render this template
});
  • Add the <Post/> component to our HTML, and use the v-for directive to iterate over our global array of posts
<Post v-for="post in posts" :post="post"></Post>

See the Pen Componentization - Vue JS by Matt Rothenberg (@mattrothenberg) on CodePen.

Implementation — React JS

Here’s the game plan:

  • Make a stateless functional component called <Post> that accepts one post as a property
const Post = ({post}) => {
  return(
    <div className="bg-white ba b--black-10 pa3 mb3">
      <div className="flex">
        <img className="mr2" src={post.avatar} alt="" />
        <div>
          <h1 className="f6 mv0 blue">{post.name}</h1>
          <ul className="mb0 mt1 pl0 list f6">
            <li className="dib black-50">{post.timeago}</li>
          </ul>
        </div>
      </div>
      <p className="f3 fw3 mv3">
        { post.status }
      </p>
    </div>
  )
}
  • Make another stateless functional component called <PostList> that accepts an array of posts as a property and maps over it, returning individual <Post> components accordingly
const PostList = ({posts}) => {
  return(
    <div>
      {
        posts.map((post) => {
          return <Post post={post}/>
        })
      }
    </div>
  )
}

See the Pen Componentization - React JS by Matt Rothenberg (@mattrothenberg) on CodePen.

Footnotes