Raphael Ugwu Writer, software engineer, and a lifelong student.

Handling server-side applications with Nuxt’s Composition API

4 min read 1246

Handling server side applications with Nuxt’s Composition API

Recently, there has been an increase in the adoption of Vue’s Composition API in the ecosystem. Its ability to maintain components as they grow and also its encouragement of reusing components comes in handy in lots of large projects. Due to server-side rendering, projects written in Nuxt have a hard time using Vue’s Composition API. The Nuxt team observed this and put together a composition API for projects written in Nuxt. In this article, we’ll take a look at how the Nuxt Composition API works, its leverage over Vue’s Composition API, and best practices for using it in projects.

Getting started

To add Nuxt’s Composition API to your project, install it like you would install a plugin:

npm install @nuxtjs/composition-api --save

/*  For Yarn users */

yarn add @nuxtjs/composition-api

When this is successfully done, enable the module in your Nuxt config file:

{
  buildModules: [
    '@nuxtjs/composition-api'
  ]
}

Handling application data

The main challenges users encounter when using Vue’s Composition API in Nuxt projects comes from data not being returned during communication between the server and client sides of the application. Let’s say we have data that we want to retrieve from an API and display on a Nuxt app:

import { ref } from '@nuxtjs/composition-api'

function useTodo () {
  const todo = ref({})

  const fetchPost = async (id) => {
    fetch('https://gorest.co.in/public-api/todos/' + user_id)
      .then(response => response.json())
      .then(json => post.value = json)
  }

  return {
    todo,
    fetchTodo
  }  
}

When we try to import and use the useTodo function in our Nuxt application, the data retrieved from the API fails to get to the server-side because the basic action of fetching the data is asynchronous while, by default, server-side implementations run synchronously. Thus the code sample below will return an empty div:

<template>
  <div>{{ data.title }}</div>
</template>

<script>
import { useTodo } from '@/composables'

export default defineComponent({
  setup (props, { root }) {
    const { todo, fetchTodo } = useTodo($root.route.params.user_id)

    fetchTodo()

    return { todo }
  }
})
</script>

Nuxt’s Composition API provides a wrapper called useFetch for fetching data from the server side and relaying it to the client side. It does a useful job in preventing multiple asynchronous network calls as it ensures navigation is done just once on the server side and the resulting data is retrieved by our client-side code and used as its initial state. Using a mock REST API sample, let’s take a look at how we can retrieve data with the useFetch wrapper:

import { defineComponent } from '@nuxtjs/composition-api'
import { ref, useFetch } from '@nuxtjs/composition-api'

function useTodo (id) {
  const todo = ref({})

  const { fetch: fetchTodo } = useFetch(async () => fetch('https://gorest.co.in/public-api/todos/' + user_id)
    .then(response => response.json())
    .then(json => todo.value = json)
  )

  return {
    post,
    fetchTodo
  }  
}

In the code block above, useFetch returns fetchTodo – a fetch function used to make our asynchronous call. Once this call is made the first time, our server-side code will contain our list of todos:

<div key="0">
  Aggredior the testimony of the multitude, therefore I will restore the color of whic   h I see.
</div>

Accessing additional modules with Nuxt Context

The Composition API also provides the ability to access properties provided by Nuxt Context such as a store, route, or environmental variables. It does this via a wrapper called useContext – which can also access Nuxt module properties. Let’s see how context makes use of the nuxtjs/axios module to make a request. The first thing we’ll do is install the module we want to access properties from:

npm install @nuxtjs/axios

Next, we’ll add it to our Nuxt configuration file:

// nuxt.config.js

export default {
  modules: [
    '@nuxtjs/axios',
  ],

  axios: {
    // proxy: true
  }
}

Then we call the $axios property to make use of the module. Let’s try to swap the native fetch method in our previous fetchTodo example with @nuxt/axios:

import { defineComponent } from '@nuxtjs/composition-api'
import { ref, useFetch, useContext } from '@nuxtjs/composition-api'

function useTodo (id) {
  const todo = ref({})
  const { @axios } = useContext()

  const { fetch: fetchTodo } = useFetch(async () =>
      todo.value = await $axios.$get('https://gorest.co.in/public-api/todos/' + id)

  return {
    post,
    fetchTodo
  }  
}

Updating headers and HTML attributes

The Composition API provides a usemeta() Hook which enable you to interact directly with your application’s header properties and meta tags. With useMeta(), you can set and restrict the modification of your header’s state to one component only. Let’s take a look at how this works:

<template>
  <div>
    Welcome Back
    <nuxt />
  </div>
</template>

import {
  defineComponent,
  useContext,
  useMeta,
  watchEffect,
} from "nuxt-composition-api";

export default defineComponent({
  name: "Home",
  head: {},
  setup() {
    const { route } = useContext();
    const { title } = useMeta();
    watchEffect(() => {
      title.value = route.value.path;
    });
  },
});
</script>

In the code sample above, we make use of the useMeta() tag to set our header value to the route defined by the useContext wrapper – we can go a step further by defining the routes and personalizing their headers as well:

// StudentProfile.vue

<template>
  <div>
    Student's Profile
    <nuxt-link to="/Grades">Grades</nuxt-link>
  </div>
</template>
<script lang="ts">
import { defineComponent, useMeta } from "nuxt-composition-api";
export default defineComponent({
  name: "StudentProfile",
  head: {},
  setup() {
    const { title } = useMeta();
    title.value = "Here is your profile";
  },
});
</script>

The value assigned to title.value via the useMeta tag then defines our header for whichever route is being viewed. Also, note that it’s important that the head property is declared for the useMeta tag to work:

// Grades.vue

<template>
  <div>
    Grades
    <nuxt-link to="/StudentProfile">Student's Profile</nuxt-link>
  </div>
</template>
<script lang="ts">
import { defineComponent, useMeta } from "nuxt-composition-api";
export default defineComponent({
  name: "Grades",
  head: {},
  setup() {
    const { title } = useMeta();
    title.value = "View your grades here";
  },
});
</script>

On the browser, this is how it would look:

Performance precautions with the Composition API

Nuxt’s Composition API is strict in fact-checking and as such, there are rules to be adhered to during usage. One of such rules is to ensure a unique key is used alongside helper functions such as useAsync and ssrRef when they are applied within global composables. Failure to impose a unique key for the concerned function could lead to constants or variables adopting values not assigned to them. Take a look at the code sample below:

function useTodo() {

// Only one unique key is generated, no matter how many times this function is called.

    const todo = ssrRef('')

    return todo
}

const a = useTodo()
const b = useTodo()

b.value = 'Buy Gas'

In the above code sample, if a unique key isn’t set, the value of a will also be initialized to Buy Gas on the client-side. This can be prevented if the useTodo function is assigned a key:

function useTodo(path: string) {
    const task = useAsync(
        () => fetch(`https://api.com/slug/${path}`).then(r => r.json()),
        path,
    )

    return {
        task
    }
}

export default useTodo

Conclusion

Nuxt’s Composition API was created out of the necessity of handling composition in server-side applications more seamlessly. Though its adoption is still in the early stages – it wouldn’t be surprising to see it support huge projects and have similar success to Vue’s Composition API. Should you need to take a look at the code demo for an example in this post – you can check it out here.

Experience your Vue apps exactly how a user does

Debugging Vue.js applications can be difficult, especially when there are dozens, if not hundreds of mutations during a user session. If you’re interested in monitoring and tracking Vue mutations for all of your users in production, try LogRocket. https://logrocket.com/signup/

LogRocket is like a DVR for web and mobile apps, recording literally everything that happens in your Vue apps including network requests, JavaScript errors, performance problems, and much more. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred.

The LogRocket Vuex plugin logs Vuex mutations to the LogRocket console, giving you context around what led to an error, and what state the application was in when an issue occurred.

Modernize how you debug your Vue apps - .

Raphael Ugwu Writer, software engineer, and a lifelong student.

Leave a Reply