Why people got upset with Vue 3

Written by Alex Kyriakidis

Monday I woke to see a ton of people tweeting about some new feature of Vue 3! I get excited and see this tweet from Evan You, the creator of Vue, in the event you didn't know.


Vue darkest day? That sounds like a funny article. 👀 I open the link and to my surprise, I realize this is no joke. It seems like the Vue community is really pissed with this new feature. People all around Reddit and HackerNews write about Vue getting complex, bad, or even non-developer friendly.

I get alarmed at once! I was offline for a weekend and now Vue gets complex all of a sudden? 😳

I run to the computer to read the Function-based Component API RFC (request for comments). The first thing to notice is the massive ratio of positive/negative reactions, approximately 5:1 at the time of writing.

But that doesn’t make sense. That cannot be a dark day. But what really changes? What is this Function-based Component API that so many people are talking about?

By taking a look at the first code block, my minds stops for a minute.

<template>
  <div>
    <span>count is {{ count }}</span>
    <span>plusOne is {{ plusOne }}</span>
    <button @click="increment">count++</button>
  </div>
</template>

<script>
  import { value, computed, watch, onMounted } from 'vue'

  export default {
    setup() {
      // reactive state
      const count = value(0)
      // computed state
      const plusOne = computed(() => count.value + 1)
      // method
      const increment = () => { count.value++ }
      // watch
      watch(() => count.value * 2, val => {
        console.log(`count * 2 is ${val}`)
      })
      // lifecycle
      onMounted(() => {
        console.log(`mounted`)
      })
      // expose bindings on render context
      return {
        count,
        plusOne,
        increment
      }
    }
  }
</script>

What? What the hell is that? Where are the data defined? Why is computed a function?

While still in shock, I am going to fill a cup of coffee.

I go back to the computer and continue reading the rendered version of the RFC this time. So, everything lives in a setup function and I can write anything (data, methods, lifecycle hooks, etc) in any order, like writing a vanilla javascript application. This looks somewhat chaotic but the flexibility sounds insane. I jump to the Comparison with 2.x API code examples in the bottom of the RFC to get to the meat asap.

Fetching Data Based on Prop

Standard API

<template>
    <div>
        <template v-if="isLoading">Loading...</template>
        <template v-else>
            <h3>{{ post.title }}</h3>
            <p>{{ post.body }}</p>
        </template>
    </div>
</template>

<script>
    import { fetchPost } from './api'

    export default {
      props: {
        id: Number
      },
      data() {
        return {
          isLoading: true,
          post: null
        }
      },
      mounted() {
        this.fetchPost()
      },
      watch: {
        id: 'fetchPost'
      },
      methods: {
        async fetchPost() {
          this.isLoading = true
          this.post = await fetchPost(this.id)
          this.isLoading = false
        }
      }
    }
</script>

Functions API

    <template>
      <div>
        <template v-if="isLoading">Loading...</template>
        <template v-else>
          <h3>{{ post.title }}</h3>
          <p>{{ post.body }}</p>
        </template>
      </div>
    </template>

    <script>
    import { value, watch } from 'vue'
    import { fetchPost } from './api'

    export default {
      setup(props) {
        const isLoading = value(true)
        const post = value(null)

        watch(() => props.id, async (id) => {
          isLoading.value = true
          post.value = await fetchPost(id)
          isLoading.value = false
        })

        return {
          isLoading,
          post
        }
      }
    }
    </script>

The first surprise here is the length of the code. I’d clearly expect the function based API to be more lines than the traditional Object API. Object-based 40 vs Function-based 32. 👌

Both examples here, implement the functionality of a component that accepts the id of a post as a prop, and it fetches the post when the id changes.

I want to break down the setup method to truly realize what's going on. So, in the Function-based component API, the setup method gets the prop as an argument and the data are defined using this value function that is imported from vue.

    import { value, watch } from 'vue'
    import { fetchPost } from './api'

    export default {
      setup(props) {
        const isLoading = value(true)
        const post = value(null)
            //....
        }
    }

Then there is this funky watch function call that listens for changes in props.id and it makes a AJAX call every time the id changes.

watch(() => props.id, async (id) => {
  isLoading.value = true
  post.value = await fetchPost(id)
  isLoading.value = false
})

Lastly, setup returns an object with the reactive state of the component, just like the data method.

export default {
  setup(props) {
    const isLoading = value(true)
    const post = value(null)

    watch(() => props.id, async (id) => {
      isLoading.value = true
      post.value = await fetchPost(id)
      isLoading.value = false
    })

    return {
      isLoading,
      post
    }
  }
}

That's not bad, right? I continue reading, to reach the Motivation section. Here there is this beatiful example of breaking the component into functions.

function useMouse() {
  const x = value(0)
  const y = value(0)
  const update = e => {
    x.value = e.pageX
    y.value = e.pageY
  }
  onMounted(() => {
    window.addEventListener('mousemove', update)
  })
  onUnmounted(() => {
    window.removeEventListener('mousemove', update)
  })
  return { x, y }
}

// in consuming component
const Component = {
  setup() {
    const { x, y } = useMouse()
    const { z } = useOtherLogic()
    return { x, y, z }
  },
  template: <div>{{ x }} {{ y }} {{ z }}</div>
}

Oh my god! At this point, I realize the Function-based Component API is genius. So no more insanely long code components.

Truth is that components in big applications can get really crazy. I've worked with several teams on big projects and I have to say the component length with the object API is something that becomes problematic for many. I've seen well-written components consisting of 1000s lines - nobody wants to refactor that. 🙈

Additionally, the Function-based API is naturally type-friendly. I know a lot of Typescript users that will cry tears of joy when they hear the news.

Human Thoughts

The Vue team devotes an insane amount of time maintaining and improving the framework and it's sad seeing the community getting upset, many times without even reading the proposal. People on Reddit and HN might get toxic sometimes but this shouldn't shape your opinion without you being educated on the subject.

It is exactly the same as the news we get from the internet and TV. How often are they accurate or even real? We have to do research in order to find out.

My recommendation, mostly for maintaining your mental health, is to receive this kind of news with a grain of salt and in a positive way since no one wants to make their software or framework worse. The Vue team could easily stick to the Vue 2 API forever, without having to do daily research, develop new strategies, write new documentation, yadda, yadda, yadda. What's happening is for your own good, even if that's not clear on the first sight.

What would you prefer? Stick to an API that the team believes is limiting and see the next billion-dollar companies like Facebook picking another framework because Vue is not flexible enough for them?

RFCs are for everyone

Vue.js is an Open Source project. Everyone is welcome and actually encouraged to participate in the discussion for future features and changes. Thus, we call these discussion RFCs - Request for Comments.

I am curious what you think about the Function-based Component API. I got scared when I first heard about it but the more I read it and played around with it I came to get excited. If you like it, head over to the RFC and hit the 👍so the team and other people know the thoughts of the community!

If you don't like it, that's fine. 🙂Read the proposal and go through the comments carefully to see what other people say and if not covered, leave a comment with your concerns. The Vue team is more than happy to receive feedback and discuss with Vue developers.

This is not Set in stone 🧗‍♀️

This is an RFC (Request for Comments) - as long as this pull request is still open, this is just a proposal for soliciting feedback. We encourage you to voice your opinion, but please actually read the RFC itself before commenting, as the information you got from a random Reddit/HN thread can be incomplete, outdated or outright misleading.

Closing

Just for the record, the Object API is lovely so I can see why so many got angry. Another thing to notice though is that many people don't read the full RFC or skim through the headlines on reddit and that's enough for them shout on Twitter or troll on GitHub. The RFC states that the Object-based API is here to stay.

Personally, I can't wait for the Function-based API to be finalized and released and put all the possibilities in action. I am sure all the teams I am consulting will be excited to get this new superpower in their hands. 🦹‍♀️

Don't be surprised by Vue 3! Sign up to Vue School to be the first to receive our upcoming in-depth Vue.js 3 Masterclass on the newest version of Vue.js. In the meantime, if you are looking for Advanced Reusable Component Patterns make sure to follow our course to be notified when it's launched.

Leave a Reply

Your email address will not be published. Required fields are marked *

Up Next:

Student Pricing at Vue School

Student Pricing at Vue School