Home

Vue computed getters and setters

April 15, 2018

I figured out I’d post a short note about a feature I find very useful with Vue computed properties.

Have you ever been in a situation where you need to integrate a third-party component which emits data in a very inconvenient format for your application? Let’s say that you’ve got a location fetcher component that exposes a lot of data:

{
  latitude: 44.427998,
  longitude: 26.098756,
  city: "Bucharest",
  country: "Romania"
}

Let’s say that your component is deeply nested and it only needs to emit country and city to the outside, while also ignoring the rest of the noise (note: I’m using JSX for writing Vue components here, which may look a bit strange). One more requirement is it also needs to pass the country and city back to the third party component, just to complicate things a bit.

import ThirdPartyLocationFetcher from './ThirdPartyLocationFetcher.js'

export default {
  name: 'DeeplyNestedComponent',
  props: ['map_data'],

  render() {
    return (
      <div>
        <ThirdPartyLocationFetcher
          // Pass just the filtered data somehow
          map_data={...}
          onInput={unfilteredData => {
            // Filter and emit a new event
          }}
        />
      </div>
    )
  },
}

A very neat solution for this problem is to create a computed property with a custom setter and getter. In short, this is very useful when you need to have intermediate representations of other, more complex, values. They have a very short lifespan and they’re very easy to reason about. Setters and getters just get the job done, without asking too much. A very extensive documentation on those can be find on vuejs.org website. Here I’m going to show how to solve our little problem with them:

export default {
  name: 'DeeplyNestedComponent',
  props: ['map_data'],
  computed: {
    filteredMapData: {
      set({country, city}) {
        this.$emit('newMapData', {country, city})
      },

      get() {
        return this.map_data
      },
    },
  },
  render() {
    return (
      <div>
        <ThirdPartyLocationFetcher
          map_data={this.filteredMapData}
          onInput={unfilteredData => (this.filteredMapData = unfilteredData)}
        />
      </div>
    )
  },
}

Here we filter just the needed part, using ES6 arguments destructuring and just pass the resulting data up the events chain. Below I’m having a complete but very simplistic demo using this technique.

Make sure to check out src/components/DeeplyNestedComponent.js file.

Simple and gets the job done. Now you can go home, take a rest.


Andrei Glingeanu

Andrei Glingeanu's notes and thoughts. You should follow him on Twitter, Instagram or contact via email. The stuff he loves to read can be found here on this site or on goodreads.