Code360 powered by Coding Ninjas X Naukri.com. Code360 powered by Coding Ninjas X Naukri.com
Table of contents
1.
Introduction
2.
What is setup? Why do we need it?
3.
The props argument of setup
4.
The context argument of setup
4.1.
context.attrs
4.2.
context.slots
4.3.
context.emit
5.
FAQs
6.
Key Takeaways
Last Updated: Mar 27, 2024

Composition API Setup

Author Toohina Barua
0 upvote

Introduction

Imagine your plan for the day is buying a pair of shoes and a dress, watching a movie, and having food. Now, we can go about this plan in two ways. The first way is to visit the shoe store, then the dress showroom, go to a theatre to watch the movie, and finally visit a restaurant to eat food. In this way, our day is divided into small tasks, and there are different places where each task will be performed. It sounds like too much work, right? This way is like the options API in Vue.js, where you partition your code and put it under different component options. The second way is to just go to a mall where everything is in the same place, just like the setup function of composition API in Vue.js! If you are wondering how then you have come to the right place! Let’s dive into the topic of Composition API Setup.

What is setup? Why do we need it?

In the options API in Vue, we have different component options that would divide our code logic into bits and pieces. Let’s see an example of options API through code. 

Create a vue App using the following command in the terminal:

vue create setup-demo

Change directory (cd) to the setup-demo and start the App at localhost:8080 using the following command:

npm run serve 

Delete the HelloWorld.vue file and make OptionsAPIDemo.vue, CompositionAPIDemo.vue, PropsDemo.vue, ContextAttrs.vue, ContextEmit.vue, and ContextSlots.vue inside the components folder so that your file structure looks like this:

 

OptionsAPIDemo.vue

We see in the code below that we have divided our code for displaying a message into many component options. For instance,

- The props that are passed as attributes from the parent component to the child component will come under the props.

- The property we will work on (the message) is put in the data option.

- The three methods: Joke(), Question(), Fact() are under the methods option.

- The watch option will look for any changes in the message and log it onto the console.

- We have a separate option to compute the message with four more exclamatory marks at the end of the it. 

- We have a different option for the console.log statement when the component is mounted.

<template>

    <div id="options-api-div">

        <h2>This is the demo of options API</h2>

        <h4>{{message}}</h4>

        <h4>{{longerMessage}}</h4>

        <h4></h4>

        <button @click="Joke()">Tell me a joke</button>

        <button @click="Question()">Ask me a question</button>

        <button @click="Fact()">Tell me a fact</button>

    </div>

</template>

<script>

export default{

    name:"OptionsAPIDemo",

    props:["content"],

    data(){

        return {

            message:this.content,

        }

    },

    methods:{

        Joke(){

           this.message="Q. What is the object oriented way to become wealthy? Ans. Inheritance!"  

        },

        Question(){

            this.message="Q. Why use setup() in Vue?"

        },

        Fact(){

            this.message="NASA still operates some projects on programming from the 1970’s"

        }

    },

    watch:{

        message:function (newMessage) {

        console.log(newMessage);

        }

    },

    computed:{

        longerMessage:function () {

            return this.message+"!!!!"

        }

    },

    mounted:function () {

        console.log("OptionsAPIDemo component mounted");

    }

}

</script>

<style>

#options-api-div{

    border-radius: 30px;

    padding:30px;

    margin:40px;

    background-color: pink;

    color:rgb(219, 84, 106);

    box-shadow:5px 5px 5px rgb(170, 170, 170);

}

</style>

However, in real life, the programs won’t be so simple. In the example above, the code wants to display some messages depending on the button clicked. Partitioning a huge code into several options would be tedious. Using Options API reduces the readability of large programs and makes them difficult to maintain. To overcome this problem, the composition API introduced a function called setup. With the setup function, the code can now be organized by logical concerns. Let us have a look at this with an example:

CompositionAPIDemo.vue

<template>

    <div id="composition-api-div">

        <h2>This is the demo of composition API</h2>

        <h4>{{message}}</h4>

        <h4>{{longerMessage}}</h4>

        <h4></h4>

        <button @click="Joke()">Tell me a joke</button>

        <button @click="Question()">Ask me a question</button>

        <button @click="Fact()">Tell me a fact</button>

    </div>

</template>

<script>

import { ref, onMounted, computed, watch } from "vue";

export default{

    props:["content"],

    setup(props){

        const message=ref(props.content)

        function Joke(){

           message.value="Q. What is the object oriented way to become wealthy? Ans. Inheritance!"  

        }

        function Question(){

            message.value="Q. Why use setup() in Vue?"

        }

        function Fact(){

            message.value="NASA still operates some projects on programming from the 1970’s"

        }

        const longerMessage = computed(function(){return message.value+"!!!!"});

        watch(message,function(newMessage){

            console.log(newMessage);

        })

        onMounted(function(){console.log("CompositionAPIDemo Mounted")})

        return{message,longerMessage,Joke,Question,Fact}

    }

}

</script>

<style>

#composition-api-div{

    border-radius: 30px;

    padding:30px;

    margin:40px;

    background-color: rgb(192, 255, 236);

    color:rgb(84, 199, 219);

    box-shadow:5px 5px 5px rgb(170, 170, 170);

}

</style>

The setup method is executed before the CompositionAPIDemo component is created and once the props are resolved. Setup()  returns an object with all of its properties which the component can use. As you can see, the setup function has composition functions within it. Let us complete the rest of the code and see the results.

App.vue

<template>

  <div>

    <h1>Setup</h1>

    <OptionsAPIDemo content="This is the content of OptionsAPIDemo"/>

    <CompositionAPIDemo content="This is the content of CompositionAPIDemo"/>

  </div>

</template>

<script>

import OptionsAPIDemo from "./components/OptionsAPIDemo.vue"

import CompositionAPIDemo from "./components/CompositionAPIDemo.vue"

export default {

  name: 'App',

  components: {

    OptionsAPIDemo,

    CompositionAPIDemo

  }

}

</script>

<style>

#app {

  font-family: Avenir, Helvetica, Arial, sans-serif;

  text-align: center;

}

button{

    border-radius: 5px;

    background-color:rgb(255, 98, 125);

    color:white;

    font-size:15px;

    box-shadow: 5px 5px 15px grey;

    border:none;

    padding:15px;

    margin:10px;

}

button:hover{

    box-shadow: none;

}

</style>

localhost:8080

When we click on the Tell me a joke button:

When we click on the Ask me a question button:

When we click on the Tell me a fact button:

Console:

The props argument of setup

Using props, we can influence the DOM of a component by passing the properties as attributes from other components. The props parameter of setup gives access to all props of the component. The data option is not needed when we use setup. However, all the variables the setup method returns are not reactive by default. We will get an error if we try to make a non-reactive variable in the setup method like so:

So to get rid of this error, we will use the reactive or ref method to make these variables reactive.

PropsDemo.vue

When we do not use ref or reactive methods on our variable and try to change its value, the change is reflected inside the setup method but not on the frontend. In the code below, we change the title.value using the setTimeout function after three seconds. If we do not use reference, the title.value will change, but it will not reflect this change on the frontend.

We are giving the initial value of title from the prop passed from App.vue, in this case, the topic. 

<template>

    <div>

        <h2>{{title}}</h2>

    </div>

</template>

<script>

import {ref} from "vue"

export default{

    props:["topic"],

    setup(props){

        console.log("topic:", props.topic)

        const title=ref(props.topic)

        console.log("title:"title)

        setTimeout(function(){

            title.value="Props title change"

            console.log("After Changing title:",title.value)},3000)

        return {title}

    }

}

</script>

App.vue

<template>

  <div>

    <h1>Setup</h1>

    <PropsDemo topic="The topic is Props Parameter in setup"/>

  </div>

</template>

<script>

import PropsDemo from "./components/PropsDemo"

export default {

  name: 'App',

  components: {

    PropsDemo

  }

}

</script>

localhost:8080 (Before 3 seconds)

Console (Before 3 seconds)

localhost:8080 (After 3 seconds)

Console (After 3 seconds)

The context argument of setup

The setup method accepts two arguments: props and context. We talked about props a lot in the previous sections. Now, we will look at the second parameter, context. A context is a Javascript object with other values that might be useful inside the setup method. The context object has three features:

  • Attributes
  • Slots
  • Emits


Let us look at each of these properties in detail.

context.attrs

These are attributes of the component, excluding the props. These are not registered under props and are non-reactive by default when we use them inside the setup method.

ContextAttrs.vue

<template>

    <h2>{{h2}}</h2>

</template>

<script>

import {ref} from "vue"

export default{

    props:["heading"],

    setup(props,context){

        console.log(props.heading)

        const h2=ref(props.heading)

        console.log(context.attrs)

        return {h2}

    }

}

</script>

App.vue

<template>

  <div>

    <h1>Setup</h1>

    <ContextAttrs heading="This is a demonstration of context.attrs" index="one" @someFunc="someFunc"/>

  </div>

</template>

<script>

import ContextAttrs from "./components/ContextAttrs.vue"

export default {

  name: 'App',

  components: {

    ContextAttrs

  },

  methods: {

    someFunc(){

      console.log("Hello")

    }

  }

}

localhost:8080

Console

context.slots

Using this we can directly influence the DOM like we can decide which html tags our information should be in.

ContextSlots.vue

<template>

    <div>

    </div>

</template>

<script>

import {h} from "vue"

export default{

    props:["tagname"],

    setup(props,context){

        return function(){

            return h(props.tagname,

            {}//props and attributes: OPTIONAL

            context.slots.default()//rendering default slot

            )

        }

    }

}

</script>

App.vue

<template>

  <div>

    <h1>Setup</h1>

    <ContextSlots tagname="h1">Slots are awesome!</ContextSlots>

  </div>

</template>

<script>

import ContextSlots from "./components/ContextSlots.vue"

export default {

  name: 'App',

  components: {

    ContextSlots

  }

}

</script>

localhost:8080

context.emit

The context.emit is used in place of $this.emit. It is used to send events from one component to the other.

ContextEmit.vue

<template>

    <div>

        <button @click="toggle">Show Message</button>

    </div>

</template>

<script>

export default{

  setup(props,context){

      console.log(props)

      function toggle(){

          context.emit("click-to-toggle")

      }

      return {toggle}

  }

}

</script>

App.vue

<template>

  <div>

    <h1>Setup</h1>

    <ContextEmit @click-to-toggle="handleToggle"/>

  </div>

</template>

 

<script>

import ContextEmit from "./components/ContextEmit.vue"

export default {

  name: 'App',

  components: {

    ContextEmit

  },

  methods:{

    handleToggle(){

      console.log("handleToggle")

    }

  }

}

</script>

 

<style>

#app {

  font-family: Avenir, Helvetica, Arial, sans-serif;

  text-align: center;

}

button{

    border-radius: 5px;

    background-color:rgb(255, 98, 125);

    color:white;

    font-size:15px;

    box-shadow: 5px 5px 15px grey;

    border:none;

    padding:15px;

    margin:10px;

}

button:hover{

    box-shadow: none;

}

</style>

localhost:8080

Console

FAQs

1. Why should we avoid using this keyword inside setup? 
Ans. The keyword this should not be used inside the setup method because it will not refer to the component instance. The setup() is called before data properties, computed properties, or methods are resolved. Therefore they aren't accessible during setup().

2. What are the advantages of composition API?
Ans. The advantages of composition API are:

  • It makes large codes readable and maintainable using the setup function.
  • It allows the reuse of code using composition functions.
  • It supports typescript.
     

3. When setup is executed, what are the component options we have and do not have access to?
Ans. The component instance isn’t yet created when we execute the setup function. Thus we have access to component options: props, attrs, slots, and emit. We do not have access to component options: data, computed, methods, and refs (template refs).

Key Takeaways

We learned the advantages of composition API over options API from this article. We studied how setup from the composition API helps improve readability. We looked in detail into the arguments that the setup function accepts. We saw a lot of coding examples on using the setup function.  If you want to learn more about Vue.js, you can read our articles on Vue.js or take our highly curated Web Development course.

Live masterclass