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

Inertia.js + Vue 3 SSR:服务端预取数据客户端重置问题咨询

Inertia.js + Vue 3 SSR:服务端预取数据后客户端被重置的问题分析与解决

场景与代码

我用Inertia.js + Vue 3实现SSR,希望在服务端渲染阶段预取并设置数据,编写的代码如下:

<template>
  data: {{myData}}
</template>
<script setup>
import {ref} from "vue";

const isServer = typeof window === 'undefined'
const myData = ref(null)

if (isServer) {
  console.log('on server')
  myData.value = 'data from server'
} else {
  console.log('on client')
  if (myData.value === null) {
    myData.value = 'data is null'
  }
}
</script>

当前现象

  • 服务端与客户端的日志均能正常打印
  • 浏览器中myData初始显示为data from server,但很快变为data is null
  • 页面源码里myData显示的是data from server

疑问与预期

  • 客户端渲染时myData是不是被重新定义成null了?这属于正常行为吗?
  • 是不是SSR无法实现预取数据?
  • 预期效果:客户端渲染时显示骨架屏并执行局部重载;SSR时完成完整渲染,无局部重载

问题分析

  1. 客户端数据重置的原因
    这是SSR水合(Hydration)机制的正常表现:服务端仅生成静态HTML字符串,客户端加载页面后会重新创建Vue组件实例——你的myData在客户端会被重新初始化为ref(null),随后进入else分支,因为此时myData.value为null,所以被替换成data is null。服务端设置的myData值没有被序列化传递到客户端,客户端完全是重新初始化的状态,因此会覆盖服务端渲染的HTML内容。

  2. 是否属于正常行为
    你的代码逻辑导致的结果是SSR机制下的“正常现象”,但这不是正确的SSR数据传递方式。SSR的核心是服务端将预取数据序列化后传递给客户端,让客户端在水合时复用这些数据,而非两端各自初始化。

  3. SSR可以预取数据,只是方式错误
    SSR完全支持预取数据,只是你没有利用Inertia.js提供的SSR数据传递机制。


解决方案

1. 利用Inertia服务端Props传递预取数据(推荐)

Inertia.js在SSR时会自动将服务端返回的props序列化并传递给客户端,客户端通过usePage()即可获取这些数据,无需重新初始化。

服务端示例(以Laravel为例):

在控制器中预取数据,通过Inertia返回:

public function show()
{
    // 服务端预取数据
    $myData = 'data from server';
    return Inertia::render('YourPage', [
        'myData' => $myData,
    ]);
}

客户端Vue组件:

<template>
  <div v-if="!pageProps.myData">
    <!-- 骨架屏 -->
    <div class="skeleton">Loading...</div>
  </div>
  <div v-else>
    data: {{ pageProps.myData }}
  </div>
</template>
<script setup>
import { usePage } from '@inertiajs/vue3';
import { onMounted } from 'vue';

const page = usePage();
const pageProps = page.props;

// 客户端局部重载逻辑(可选)
onMounted(() => {
  // 可在此发起请求更新数据,示例:
  // fetch('/api/data').then(res => res.json()).then(data => pageProps.myData = data);
});
</script>

2. 手动序列化服务端数据(特殊场景使用)

若不想通过Inertia props传递,可在服务端将数据注入全局window对象,客户端读取:

服务端模板示例(如Blade):

<script>
  window.__INITIAL_DATA__ = {
    myData: '{{ $myData }}'
  };
</script>

客户端组件:

<template>
  <div v-if="!myData">
    <!-- 骨架屏 -->
    <div class="skeleton">Loading...</div>
  </div>
  <div v-else>
    data: {{ myData }}
  </div>
</template>
<script setup>
import { ref, onMounted } from 'vue';

const isServer = typeof window === 'undefined';
const myData = ref(null);

if (isServer) {
  // 服务端预取数据
  myData.value = 'data from server';
} else {
  // 客户端读取全局初始数据
  myData.value = window.__INITIAL_DATA__.myData;
  
  // 客户端局部重载逻辑
  onMounted(() => {
    // 可在此发起请求更新数据
  });
}
</script>

3. 骨架屏与无局部重载的实现

  • SSR场景:服务端传递myData后,客户端水合时直接复用数据,会直接渲染内容,不会显示骨架屏,也无局部重载。
  • 客户端路由跳转场景:Inertia会发起AJAX请求获取props,此时可在组件中判断pageProps.myData是否存在,显示骨架屏直到数据返回后渲染内容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 12:17:27