Monday, April 9, 2018

Vue.js and functional single file components

Single file components (SFC) is probably the most powerful feature (structure-wise) in Vue.js. They are simple in nature but very powerful when it comes to bundling things together:

<template>
  <h1 class="my-header>Hello!</h1>
</template>

<script>
export default {
}
</script>

<style>
.my-header {
  color: red;
}
</style>

There are times when you want your component to be stateless. Such components are great for bundling together functionality that would otherwise be created by putting together other components. I call them template components, because they are predefined with places where you can override the defaults. Those components do not have state hence we call them stateless or functional.

The problem with SFCs is that unlike regular .vue components they don't pass data down. Especially the class and style properties are not passed automatically. To mitigate that I went through a few iterations to find the nicest solution. Here's what I came up with that seems to do the job very well. Let's assume we're creating a predefined component for animation. We want the styles to be bundled with the component so SFC is the right way to go.

<script>
export default {
  functional: true,
  render: (h, { data, children }) => (
    <transition-group { ...data } tag="ul" name="slide">
      { children }
    </transition-group>
  )
}
</script>

<style>
.slide-move {
  transition: transform 1s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
</style>

A quick explanation: { data, children } is a destructing assignment from the second parameter to 2 fields that we'll use later. Then the { ...data } means "apply all elements passed on (including but not limited to class and style).

That's all there is to it.