diff --git a/docs/1.getting-started/7.state-management.md b/docs/1.getting-started/7.state-management.md index b9a18b5dd3..c3fd299162 100644 --- a/docs/1.getting-started/7.state-management.md +++ b/docs/1.getting-started/7.state-management.md @@ -59,6 +59,10 @@ const counter = useState('counter', () => Math.round(Math.random() * 1000)) ::ReadMore{link="/docs/api/composables/use-state"} :: +::alert{icon=📘} +To globally invalidate cached state, see [`clearNuxtState`](/docs/api/utils/clear-nuxt-state). +:: + ### Advanced Usage In this example, we use a composable that detects the user's default locale from the HTTP request headers and keeps it in a `locale` state. diff --git a/docs/3.api/3.utils/clear-nuxt-data.md b/docs/3.api/3.utils/clear-nuxt-data.md index be91e5c2aa..3d677fb4d3 100644 --- a/docs/3.api/3.utils/clear-nuxt-data.md +++ b/docs/3.api/3.utils/clear-nuxt-data.md @@ -12,4 +12,4 @@ clearNuxtData (keys?: string | string[] | ((key: string) => boolean)): void ## Parameters -* `keys`: On or an array of keys that are used in `useAsyncData` to delete their cached data. If no keys are provided, **every data** will be invalidated. +* `keys`: One or an array of keys that are used in `useAsyncData` to delete their cached data. If no keys are provided, **all data** will be invalidated. diff --git a/docs/3.api/3.utils/clear-nuxt-state.md b/docs/3.api/3.utils/clear-nuxt-state.md new file mode 100644 index 0000000000..5b69b192b1 --- /dev/null +++ b/docs/3.api/3.utils/clear-nuxt-state.md @@ -0,0 +1,15 @@ +# `clearNuxtState` + +Delete cached state of `useState`. + +This method is useful if you want to invalidate the state of `useState`. + +## Type + +```ts +clearNuxtState (keys?: string | string[] | ((key: string) => boolean)): void +``` + +## Parameters + +* `keys`: One or an array of keys that are used in `useState` to delete their cached state. If no keys are provided, **all state** will be invalidated. diff --git a/packages/nuxt/src/app/composables/index.ts b/packages/nuxt/src/app/composables/index.ts index 8f154d0ebb..14343010ed 100644 --- a/packages/nuxt/src/app/composables/index.ts +++ b/packages/nuxt/src/app/composables/index.ts @@ -16,7 +16,7 @@ export { defineNuxtComponent } from './component' export { useAsyncData, useLazyAsyncData, useNuxtData, refreshNuxtData, clearNuxtData } from './asyncData' export type { AsyncDataOptions, AsyncData } from './asyncData' export { useHydration } from './hydrate' -export { useState } from './state' +export { useState, clearNuxtState } from './state' export { clearError, createError, isNuxtError, showError, useError } from './error' export type { NuxtError } from './error' export { useFetch, useLazyFetch } from './fetch' diff --git a/packages/nuxt/src/app/composables/state.ts b/packages/nuxt/src/app/composables/state.ts index 3a710ee6d3..1c44302576 100644 --- a/packages/nuxt/src/app/composables/state.ts +++ b/packages/nuxt/src/app/composables/state.ts @@ -2,6 +2,7 @@ import { isRef, toRef } from 'vue' import type { Ref } from 'vue' import { useNuxtApp } from '../nuxt' +const useStateKeyPrefix = '$s' /** * Create a global reactive ref that will be hydrated but not shared across ssr requests * @@ -20,7 +21,7 @@ export function useState (...args: any): Ref { if (init !== undefined && typeof init !== 'function') { throw new Error('[nuxt] [useState] init must be a function: ' + init) } - const key = '$s' + _key + const key = useStateKeyPrefix + _key const nuxt = useNuxtApp() const state = toRef(nuxt.payload.state, key) @@ -35,3 +36,22 @@ export function useState (...args: any): Ref { } return state } + +export function clearNuxtState ( + keys?: string | string[] | ((key: string) => boolean) +): void { + const nuxtApp = useNuxtApp() + const _allKeys = Object.keys(nuxtApp.payload.state) + const _keys: string[] = !keys + ? _allKeys + : typeof keys === 'function' + ? _allKeys.filter(keys) + : Array.isArray(keys) ? keys : [keys] + + for (const _key of _keys) { + const key = useStateKeyPrefix + _key + if (key in nuxtApp.payload.state) { + nuxtApp.payload.state[key] = undefined + } + } +} diff --git a/packages/nuxt/src/imports/presets.ts b/packages/nuxt/src/imports/presets.ts index 22aec5eae9..7e3d741f58 100644 --- a/packages/nuxt/src/imports/presets.ts +++ b/packages/nuxt/src/imports/presets.ts @@ -27,6 +27,7 @@ const appPreset = defineUnimportPreset({ 'reloadNuxtApp', 'useRuntimeConfig', 'useState', + 'clearNuxtState', 'useFetch', 'useLazyFetch', 'useCookie', diff --git a/test/bundle.test.ts b/test/bundle.test.ts index 6da01dad60..a328b6381c 100644 --- a/test/bundle.test.ts +++ b/test/bundle.test.ts @@ -36,7 +36,7 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM it('default server bundle size', async () => { stats.server = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir) - expect(roundToKilobytes(stats.server.totalBytes)).toMatchInlineSnapshot('"62.8k"') + expect(roundToKilobytes(stats.server.totalBytes)).toMatchInlineSnapshot('"62.9k"') const modules = await analyzeSizes('node_modules/**/*', serverDir) expect(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot('"2286k"')