如何在Nuxt3中实现SSR友好的带全局状态的搜索Composable
Nuxt3 SSR友好的全局搜索状态实现方案
核心思路
通过Nuxt3的useState实现搜索关键词、结果、加载状态、错误信息的全局共享,同时封装统一的搜索执行方法,确保多组件间状态同步且兼容SSR渲染。
完整的useSearch Composable实现
// composables/useSearch.js export default () => { // 全局共享状态:用唯一key标识,确保SSR时状态同步 const toSearch = useState('search_query', () => 'John') const searchResults = useState('search_results', () => null) const isLoading = useState('search_loading', () => false) const searchError = useState('search_error', () => null) // 统一搜索执行逻辑 const executeSearch = async () => { // 空关键词处理 if (!toSearch.value.trim()) { searchResults.value = null searchError.value = null return } // 更新状态:开始加载 isLoading.value = true searchError.value = null try { // 用encodeURIComponent处理搜索词,避免URL编码问题 const response = await $fetch(`https://dummyjson.com/users/search?q=${encodeURIComponent(toSearch.value)}`) searchResults.value = response } catch (err) { searchError.value = err searchResults.value = null } finally { // 无论成功失败,结束加载状态 isLoading.value = false } } return { toSearch, searchResults, isLoading, searchError, executeSearch } }
组件使用示例
搜索输入组件(任意页面/组件)
<template> <div class="search-bar"> <input v-model="toSearch" placeholder="输入关键词搜索用户" type="text" /> <button @click="executeSearch" :disabled="isLoading" > {{ isLoading ? '搜索中...' : '搜索' }} </button> </div> </template> <script setup> const { toSearch, isLoading, executeSearch } = useSearch() </script>
结果展示组件(任意页面/组件)
<template> <div class="search-results"> <div v-if="isLoading" class="loading">加载中...</div> <div v-else-if="searchError" class="error"> 搜索失败:{{ searchError.message }} </div> <div v-else-if="searchResults"> <h3>找到 {{ searchResults.users.length }} 个用户</h3> <ul> <li v-for="user in searchResults.users" :key="user.id"> {{ user.firstName }} {{ user.lastName }} </li> </ul> </div> <div v-else class="empty">请输入关键词进行搜索</div> </div> </template> <script setup> const { searchResults, isLoading, searchError } = useSearch() </script>
关键细节说明
- SSR友好性:所有状态通过
useState定义,Nuxt会自动处理服务端与客户端的状态序列化与同步,避免 hydration mismatch 问题。 - 全局状态共享:
useState的key(如search_query)是全局唯一标识,所有组件调用useSearch都会复用同一个状态实例。 - 防重复提交:通过
isLoading状态控制按钮禁用,避免用户重复点击触发多次请求。 - 错误处理:统一捕获请求错误并同步到全局状态,方便任意组件展示错误信息。
- URL编码安全:使用
encodeURIComponent处理搜索词,避免特殊字符导致的请求异常。
可选优化:结合useAsyncData缓存
如果需要复用相同关键词的搜索结果,可以将请求逻辑替换为useAsyncData,利用其缓存机制:
const executeSearch = async () => { if (!toSearch.value.trim()) { searchResults.value = null searchError.value = null return } const { data, pending, error } = await useAsyncData( // 用搜索词生成唯一key,实现不同关键词的独立缓存 `search_${toSearch.value}`, () => $fetch(`https://dummyjson.com/users/search?q=${encodeURIComponent(toSearch.value)}`), { immediate: false, // 手动触发请求 retry: 1 // 请求失败自动重试1次 } ) // 同步useAsyncData的状态到全局useState isLoading.value = pending.value searchError.value = error.value searchResults.value = data.value }
内容的提问来源于stack exchange,提问作者Tim
相关产品推荐
相关产品推荐

