Sveltekit:使用Store与localStorage刷新时数据显示异常问题
问题描述
我用localStorage做数据持久化,功能本身正常,但刷新页面时会先显示初始值0,之后才加载localStorage里的真实值。有没有办法直接获取localStorage的值,避免先显示0?还是说这个情况没法解决?
我的Store代码
import { writable } from 'svelte/store'; import { clickPower } from "$lib/store"; import { browser } from "$app/environment"; /** 这是烤肉串数量达到过的最高值 **/ export function createHighest() { const { subscribe, set } = writable(0); return { subscribe, set: (value: number) => set(value), reset: () => set(0), }; } /** 总烤肉串数量 **/ export function createTotal() { const localTotal = browser && localStorage.getItem("totalKebabs"); const totalStore = writable(localTotal ? parseInt(localTotal) : 0); const { subscribe, set, update } = totalStore; return { subscribe, // 我的其他函数写在这里 .... }; }
显示代码
{#key $totalKebabs} <span>{$totalKebabs}</span> 烤肉串 {/key}
解决方法
问题根源是Svelte/Kit的服务端渲染(SSR)逻辑:服务端执行createTotal时,browser为false,无法读取localStorage,所以store初始值设为0。等到客户端 hydration 完成后,才会加载localStorage的值,导致页面先显示0再跳转的闪烁。
方案1:修改Store,客户端初始化时直接加载本地数据
调整createTotal函数,让它在客户端环境下优先读取localStorage并更新store,避免初始值闪烁:
export function createTotal() { // 先设初始值为0,后续在客户端覆盖 const totalStore = writable(0); const { subscribe, set, update } = totalStore; // 仅在客户端执行,读取本地存储并更新 if (browser) { const savedTotal = localStorage.getItem("totalKebabs"); if (savedTotal) { set(parseInt(savedTotal)); } } // 扩展set和update方法,确保修改时同步到localStorage return { subscribe, set: (value: number) => { set(value); if (browser) { localStorage.setItem("totalKebabs", value.toString()); } }, update: (updater) => { update(prev => { const newValue = updater(prev); if (browser) { localStorage.setItem("totalKebabs", newValue.toString()); } return newValue; }); }, // 你的其他函数... }; }
方案2:在组件中用onMount初始化数据
如果不想改动store,可以在使用store的组件里,通过onMount(仅客户端执行)读取localStorage并更新store:
<script> import { onMount } from 'svelte'; import { totalKebabs } from '$lib/store'; onMount(() => { const savedTotal = localStorage.getItem("totalKebabs"); if (savedTotal) { totalKebabs.set(parseInt(savedTotal)); } }); </script> <span>{$totalKebabs}</span> 烤肉串
额外优化:减少视觉闪烁
可以给显示区域加个加载判断,直到数据加载完成再显示:
<script> import { onMount } from 'svelte'; import { totalKebabs } from '$lib/store'; let dataLoaded = false; onMount(() => { const savedTotal = localStorage.getItem("totalKebabs"); if (savedTotal) { totalKebabs.set(parseInt(savedTotal)); } dataLoaded = true; }); </script> {#if dataLoaded} <span>{$totalKebabs}</span> 烤肉串 {/if}
内容的提问来源于stack exchange,提问作者user3818418
相关产品推荐
相关产品推荐

