You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue SSR中serverPrefetch到mounted数据丢失问题求助(数据预取与状态)

Fixing Vuex State Persistence in Vue SSR

Hey there! Let's break down why your Vuex device value isn't sticking from the server to the client, and how to fix it.

Why Your Current Code Isn't Working

When dealing with Vue SSR, the server creates a new Vuex Store instance for every request, and the client spins up its own completely separate Store instance when the page loads.

Your current approach has two critical flaws:

  1. You're directly assigning this.$store.device instead of using Vuex's mutation system—this skips state tracking and best practices.
  2. Most importantly, the server's Store state never gets passed to the client. The client starts with a fresh, empty Store, so device ends up undefined in the mounted hook.

Step-by-Step Solution

1. Add a Vuex Mutation for State Updates

First, fix how you modify state by adding an official Vuex mutation (this is the only recommended way to change Vuex state):

// store/index.js
import { createStore } from 'vuex'

export function createStore() {
  return createStore({
    state() {
      return {
        device: null // Initialize the device state
      }
    },
    mutations: {
      SET_DEVICE(state, device) {
        state.device = device
      }
    }
  })
}

2. Update serverPrefetch to Use the Mutation

Modify your component's serverPrefetch to commit the mutation instead of direct assignment:

export default {
  // ...
  serverPrefetch () {
    this.$store.commit('SET_DEVICE', this.$vnode.ssrContext.device)
    console.log(this.$store.state.device) // Still logs "desktop"
  },
  mounted () {
    console.log(this.$store.state.device) // Will now log "desktop" instead of undefined!
  }
  // ...
}

3. Pass Server State to the Client (Critical Step)

This is what makes the server's state available to the client-side Store.

Server Entry File

In your server-side entry script, after handling data prefetching, attach the Store's state to the SSR context:

// server-entry.js
import { createApp } from './app'

export default async context => {
  const { app, store } = createApp()

  // Wait for all async serverPrefetch calls to finish (if any)
  await Promise.all(
    app._instance.subTree.children.map(child => {
      if (child.type.serverPrefetch) {
        return child.type.serverPrefetch.call(child.proxy)
      }
    })
  )

  // Attach store state to the context for injection into HTML
  context.state = store.state

  return app
}

HTML Template

Update your server-rendered HTML template to inject the serialized state as a global variable:

<!-- index.html (server template) -->
<!DOCTYPE html>
<html>
<head>
  <title>Vue SSR App</title>
</head>
<body>
  <div id="app">{{ html }}</div>
  <!-- Inject server state into client-side global scope -->
  <script>
    window.__INITIAL_STATE__ = ${JSON.stringify(state)}
  </script>
  <script src="/client.bundle.js"></script>
</body>
</html>

Client Entry File

Finally, initialize the client-side Store with the injected server state:

// client-entry.js
import { createApp } from './app'

const { app, store } = createApp()

// Replace client store state with the server's initial state
if (window.__INITIAL_STATE__) {
  store.replaceState(window.__INITIAL_STATE__)
}

app.mount('#app')

Quick Notes

  • Always use mutations to modify Vuex state—it ensures consistency and makes debugging easier.
  • If serverPrefetch does async work, make sure it returns a Promise so the server waits for data before rendering.
  • Avoid injecting sensitive data into __INITIAL_STATE__—it will be visible in the client's HTML source.

内容的提问来源于stack exchange,提问作者gorevanova

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 06:57:51