docs: avoid $fetch in top-level <script setup> (#19357)

This commit is contained in:
Özüm Eldoğan 2023-03-20 12:13:21 +03:00 committed by GitHub
parent b04f7dd2d5
commit d04d598ceb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -219,14 +219,24 @@ Using `<script setup lang="ts">` is the recommended way of declaring Vue compone
::ReadMore{link="/docs/api/utils/define-nuxt-component"}
::
## Isomorphic `fetch` and `$fetch`
## Using `$fetch` directly
When we call `fetch` in the browser, user headers like `cookie` will be directly sent to the API. But during server-side-rendering, since the `fetch` request takes place 'internally' within the server, it doesn't include the user's browser cookies, nor does it pass on cookies from the fetch response.
There are instances where you may need to directly call the API. Nuxt 3 provides a globally available `$fetch` method using [unjs/ofetch](https://github.com/unjs/ofetch) (in addition to `fetch`) with the same API as the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch).
Using `$fetch` has a number of benefits, including:
It will handle 'smartly' making 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.)
Plus, it comes with convenience features including automatically parsing responses and stringifying data.
::ReadMore{link="/docs/api/utils/dollarfetch"}
::
### Example: Pass Client Headers to the API
### Isomorphic `$fetch` and `fetch` calls
When we call `$fetch` in the browser, user headers like `cookie` will be directly sent to the API. But during server-side-rendering, since the `$fetch` request takes place 'internally' within the server, it doesn't include the user's browser cookies, nor does it pass on cookies from the fetch response.
#### Example: Pass Client Headers to the API
We can use [`useRequestHeaders`](/docs/api/composables/use-request-headers) to access and proxy cookies to the API from server-side.
@ -248,7 +258,7 @@ Be very careful before proxying headers to an external API and just include head
* `cf-connecting-ip`, `cf-ray`
::
### Example: Pass Cookies From Server-side API Calls on SSR Response
#### Example: Pass Cookies From Server-side API Calls on SSR Response
If you want to pass on/proxy cookies in the other direction, from an internal request back to the client, you will need to handle this yourself.
@ -274,6 +284,8 @@ onMounted(() => console.log(document.cookie))
## Best Practices
### Minimize Payload
The data returned by these composables will be stored inside the page payload. This means that every key returned that is not used in your component will be added to the payload.
::alert{icon=👉}
@ -309,6 +321,39 @@ const { data: mountain } = await useFetch('/api/mountains/everest', { pick: ['ti
</template>
```
### Avoid double calls
Calling `$fetch` in code that is executed on both server and client (such as in the top level of a `setup` function) will fetch the data twice - initially on the server and then again on the client during the hydration phase. This is because `$fetch` does not automatically serialize or transfer the data to the client.
For example:
**/pages/price.vue**: Isomorphic code below executes `$fetch` twice (initially on the server, then again on the client).
```ts
<script setup lang="ts">
const price = $fetch('/api/price');
</script>
```
**/server/api/product.get.ts**: Server only code below executes `$fetch` only once at the server side.
```ts
export default eventHandler(async (event: H3Event) => {
const price = $fetch('/api/price');
return { color: getColor(), price };
});
```
If fetching twice isn't your intended behavior, to fetch only on the server side and transfer it to the client, wrap `$fetch` with `useAsyncData()` or use `useFetch()`.
```ts
<script setup lang="ts">
const { data } = await useAsyncData('price', () => $fetch('/api/price'));
// or
const { data } = await useFetch('/api/price')
</script>
```
## Using Async Setup
If you are using `async setup()`, the current component instance will be lost after the first `await`. (This is a Vue 3 limitation.) If you want to use multiple async operations, such as multiple calls to `useFetch`, you will need to use `<script setup>` or await them together at the end of setup.
@ -342,13 +387,3 @@ export default defineComponent({
</template>
```
## Directly Calling an API Endpoint
There are instances where you may need to directly call the API. Nuxt 3 provides a globally available `$fetch` method using [unjs/ofetch](https://github.com/unjs/ofetch) (in addition to `fetch`)
with the same API as the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch).
Using `$fetch` has a number of benefits, including:
It will handle 'smartly' making 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.)
Plus, it comes with convenience features including automatically parsing responses and stringifying data.