Nuxt2.12静态项目同时使用asyncData与fetch是否属于反模式
回答
是否属于反模式
同时使用asyncData和fetch处理同一份数据请求不算标准反模式,但属于可优化的冗余实现。你当前的写法会导致首屏加载时同一份接口被调用两次,不仅浪费服务器资源,还可能出现数据返回时序不一致导致的页面内容闪动问题。
你遇到的asyncData刷新时拿不到正确语言参数的问题,本质是store的语言初始化时机晚于页面组件asyncData的执行时机,并非asyncData本身的能力限制,解决初始化逻辑后就可以避免双钩子重复请求的问题。
更优实现方案
第一步:提前同步localStorage语言到store
新增一个客户端初始化插件,在页面组件执行前就把localStorage存储的语言同步到Vuex store中:
- 新建
plugins/i18n.init.js文件:
export default ({ store }) => { // 仅客户端执行,读取localStorage的语言设置同步到store if (process.client) { const savedLang = localStorage.getItem('selectedLang') if (savedLang) { // 替换为你实际的mutation名 store.commit('language/SET_LANGUAGE', savedLang) } } }
- 在
nuxt.config.js中注册插件:
export default { plugins: [ { src: '~/plugins/i18n.init.js', mode: 'client' } ] }
该插件的执行时机早于所有页面组件的asyncData,执行后asyncData就能拿到正确的当前语言值。
第二步:合并请求逻辑,避免重复调用
把数据请求逻辑抽为公共方法,仅用asyncData处理首屏数据获取,语言切换时单独触发请求即可,优化后的组件代码如下:
// 抽离公共请求方法,避免重复编码 const getPageStory = async (slug, lang, storyApi) => { const { data } = await storyApi.get(`cdn/stories${slug}`, { language: lang }) return data.story } export default { async asyncData (context) { const slug = (context.route.path === '/' || context.route.path === '') ? '/home' : context.route.path try { const story = await getPageStory( slug, context.store.state.language.language, context.app.$storyapi ) // asyncData返回的内容会直接合并到组件data return { story } } catch (err) { context.$errorMessage( err.response, 'Sorry but this content doesn\'t exist', `Sorry, but the content called: "${context.route.name}" has a problem or doesn't exist` ) } }, data () { return { story: { content: {} } } }, watch: { // 语言切换时重新请求数据,不需要额外fetch钩子 async '$store.state.language.language' (newLang) { const slug = (this.$route.path === '/' || this.$route.path === '') ? '/home' : this.$route.path this.story = await getPageStory(slug, newLang, this.$storyapi) } } }
优化收益
- 首屏仅发起1次数据请求,保留了
asyncData的速度优势,没有冗余请求 - 避免了双请求可能导致的页面内容闪动问题
- 代码逻辑更精简,公共请求逻辑可复用在其他页面组件
内容的提问来源于stack exchange,提问作者falcosan
相关产品推荐
相关产品推荐

