使用Svelte Store进行条件渲染时SSR无法正常工作的问题咨询
嘿,这个问题我之前也碰到过——这不是预期行为,是你的实现里漏了关键的SSR适配步骤,导致渲染出问题了。
问题出在哪?
你用的普通writable store在SvelteKit的SSR流程里有个致命问题:服务器端创建的store状态和客户端的store是完全独立的两个实例,服务器不会自动把自己的store状态序列化传递给客户端。
哪怕你现在给的初始值是show: true,理论上两端初始状态一致,但只要后续有任何服务器端修改store的操作(哪怕你现在没加,后续迭代很可能会加),客户端根本不知道服务器最终渲染时用的是什么状态,直接用自己的初始值去hydrate,就会出现服务器渲染的HTML和客户端DOM不匹配的情况,Svelte就会放弃SSR的hydrate流程,直接重新渲染,看起来就像是SSR失效了。
怎么修复?
给你几个靠谱的解决方案,根据你的场景选:
方案1:用load函数传递初始状态(最通用)
先在页面的服务端load文件里定义初始状态(可以是静态值,也可以是动态计算的):
// +page.server.js export async function load() { // 这里可以根据业务逻辑动态计算show的值,比如从数据库、接口获取 return { initialShow: true }; }
然后在页面组件里用这个服务端传递的值初始化store:
<script> import { writable } from 'svelte/store'; // 接收load函数传递的data export let data; // 用服务端的初始值创建store,保证两端状态一致 const store = writable({ show: data.initialShow }); </script> {#if $store.show} <div class="view"> My conditional elements </div> {/if}
方案2:用derived store绑定页面数据
如果你的show状态完全依赖于页面的服务端数据,可以直接用derived store,省掉手动初始化的步骤:
<script> import { derived } from 'svelte/store'; export let data; // 从页面data派生store状态 const store = derived(data, ($data) => ({ show: $data.initialShow })); </script> {#if $store.show} <div class="view"> My conditional elements </div> {/if}
方案3:绑定会话状态(如果和用户会话相关)
如果show的状态是和用户会话绑定的(比如登录用户才显示),可以把状态存在session里,在hooks.server.js中处理,然后在页面里直接通过session获取并初始化store。
总结
普通的writable store不适合直接在SSR场景下使用,因为它没法在服务器和客户端之间同步状态。只要按照上面的方案,把store的初始状态和服务端传递的数据绑定起来,就能解决SSR失效的问题啦。
内容的提问来源于stack exchange,提问作者yongju lee

