--- title: Component Options description: 'Learn how to migrate from Nuxt 2 components options to Nuxt 3 composables.' --- ## `asyncData` and `fetch` Nuxt 3 provides new options for [fetching data from an API](/docs/getting-started/data-fetching). <!-- TODO: Intro to <script setup> --> <!-- TODO: Mention about options compatibility with asyncData --> ### Isomorphic Fetch In Nuxt 2 you might use `@nuxtjs/axios` or `@nuxt/http` to fetch your data - or just the polyfilled global `fetch`. In Nuxt 3 you can use a globally available `fetch` method that has the same API as [the Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) or [`$fetch`](/docs/api/utils/dollarfetch) method which is using [unjs/ofetch](https://github.com/unjs/ofetch). It has a number of benefits, including: 1. It will handle 'smartly' making [direct API calls](/docs/guide/concepts/server-engine#direct-api-calls) if it's running on the server, or making a client-side call to your API if it's running on the client. (It can also handle calling third-party APIs.) 2. Plus, it comes with convenience features including automatically parsing responses and stringifying data. You can read more [about direct API calls](/docs/guide/concepts/server-engine#direct-api-calls) or [fetching data](/docs/getting-started/data-fetching). ### Composables Nuxt 3 provides new composables for fetching data: [`useAsyncData`](/docs/api/composables/use-async-data) and `useFetch`. They each have 'lazy' variants (`useLazyAsyncData` and `useLazyFetch`), which do not block client-side navigation. In Nuxt 2, you'd fetch your data in your component using a syntax similar to: ```ts export default { async asyncData({ params, $http }) { const post = await $http.$get(`https://api.nuxtjs.dev/posts/${params.id}`) return { post } }, // or alternatively fetch () { this.post = await $http.$get(`https://api.nuxtjs.dev/posts/${params.id}`) } } ``` Within your methods and templates, you could use the `post` variable similar how you'd use any other piece of data provided by your component. With Nuxt 3, you can perform this data fetching using composables in your `setup()` method or `<script setup>` tag: ```vue <script setup lang="ts"> // Define params wherever, through `defineProps()`, `useRoute()`, etc. const { data: post, refresh } = await useAsyncData('post', () => $fetch(`https://api.nuxtjs.dev/posts/${params.id}`) ) // Or instead - useFetch is a convenience wrapper around useAsyncData when you're just performing a simple fetch const { data: post, refresh } = await useFetch(`https://api.nuxtjs.dev/posts/${params.id}`) </script> ``` You can now use `post` inside of your Nuxt 3 template, or call `refresh` to update the data. ::note Despite the names, [`useFetch`](/docs/api/composables/use-fetch) is not a direct replacement of the `fetch()` hook. Rather, [`useAsyncData`](/docs/api/composables/use-async-data) replaces both hooks and is more customizable; it can do more than simply fetching data from an endpoint. [`useFetch`](/docs/api/composables/use-fetch) is a convenience wrapper around [`useAsyncData`](/docs/api/composables/use-async-data) for simply fetching data from an endpoint. :: ### Migration 1. Replace the `asyncData` hook with [`useAsyncData`](/docs/api/composables/use-async-data) or [`useFetch`](/docs/api/composables/use-fetch) in your page/component. 2. Replace the `fetch` hook with [`useAsyncData`](/docs/api/composables/use-async-data) or [`useFetch`](/docs/api/composables/use-fetch) in your component. ## `head` :read-more{to="/docs/migration/meta"} ## `key` You can now define a key within the [`definePageMeta`](/docs/api/utils/define-page-meta) compiler macro. ```diff [pages/index.vue] - <script> - export default { - key: 'index' - // or a method - // key: route => route.fullPath - } + <script setup> + definePageMeta({ + key: 'index' + // or a method + // key: route => route.fullPath + }) </script> ``` ## `layout` :read-more{to="/docs/migration/pages-and-layouts"} ## `loading` This feature is not yet supported in Nuxt 3. ## `middleware` :read-more{to="/docs/migration/plugins-and-middleware"} ## `scrollToTop` This feature is not yet supported in Nuxt 3. If you want to overwrite the default scroll behavior of `vue-router`, you can do so in `~/app/router.options.ts` (see [docs](/docs/guide/recipes/custom-routing#router-options)) for more info. Similar to `key`, specify it within the [`definePageMeta`](/docs/api/utils/define-page-meta) compiler macro. ```diff [pages/index.vue] - <script> - export default { - scrollToTop: false - } + <script setup> + definePageMeta({ + scrollToTop: false + }) </script> ``` ## `transition` :read-more{to="/docs/getting-started/transitions"} ## `validate` The validate hook in Nuxt 3 only accepts a single argument, the `route`. Just as in Nuxt 2, you can return a boolean value. If you return false and another match can't be found, this will mean a 404. You can also directly return an object with `statusCode`/`statusMessage` to respond immediately with an error (other matches will not be checked). ```diff [pages/users/[id\\].vue] - <script> - export default { - async validate({ params }) { - return /^\d+$/.test(params.id) - } - } + <script setup> + definePageMeta({ + validate: async (route) => { + const nuxtApp = useNuxtApp() + return /^\d+$/.test(route.params.id) + } + }) </script> ``` ## `watchQuery` This is not supported in Nuxt 3. Instead, you can directly use a watcher to trigger refetching data. ```vue [pages/users/[id\\].vue] <script setup lang="ts"> const route = useRoute() const { data, refresh } = await useFetch('/api/user') watch(() => route.query, () => refresh()) </script> ```