Vue3中如何实现sessionStorage的响应式效果?
我开发了一款应用,最初每次加载或刷新页面时都会通过axios.get从数据库拉取数据,导致应用运行缓慢,因此打算仅在应用的*首次加载(initial load)*阶段获取数据并存入sessionStorage。
但sessionStorage本身不具备响应性,我最初的代码写法如下:
const state = reactive({ image: sessionStorage.image })
模板渲染逻辑:
<div class="home-image" :style="{'background-image': 'url(' + state.image + ')'}"></div>
这段代码只有在上一次页面加载时已经更新过sessionStorage的场景下才能正常运行,首次页面加载时state.image会抛出404 not found错误。我查阅了watchers、set和get的相关资料,暂时没有找到可行的实现方案。
新解决方案(无需Vuex)
我最终找到了一种不需要引入vuex,就能让sessionStorage在首次加载阶段表现出reactive特性的实现方法:
<script setup> import {reactive} from 'vue'; const state = reactive({ image: sessionStorage.image || "" }) axios.get('/home') .then(res => { const data = res.data[0] state.image = sessionStorage.image = 'storage/' + data['image'] }) </script>
实现逻辑:reactive初始化时如果sessionStorage的image为undefined,会优先使用空字符串作为默认值,等axios.get请求拿到返回数据后,同步给响应式状态state.image和sessionStorage.image赋值。后续所有页面加载时,reactive会直接读取sessionStorage中已经存储好的值,不需要重复发送请求。
编码很有乐趣,有时你能找到用1行代码替代100行代码的方法。
旧解决方案(基于Vuex实现)
这个方案实现的存储具备全局(global)、响应式(reactive)、*持久化(persistent)*三个特性,使用便捷。
步骤1:创建独立store文件
在store.js中定义全局存储:
import {createStore} from "vuex"; const store = createStore({ state() { return { image: sessionStorage.image || "" } } }) export default store
步骤2:全局注册store
在app.js中注册刚才创建的store:
require('./bootstrap'); import {createApp} from 'vue'; import app from "../vue/app"; import store from "./store"; createApp(app) .use(store) .mount("#app");
步骤3:组件中使用
<template> <section id="home" class="home"> <div class="image-container"> <div class="home-image" :style="{'background-image': 'url(' + store.state.image + ')'}"></div> </div> </section> </template> <script setup> import {useStore} from "vuex"; const store = useStore() if (!sessionStorage.image) { axios.get('/home') .then(res => { const data = res.data[0] store.state.image = sessionStorage.image = 'storage/' + data['image'] }) } </script>
方案说明
axios请求仅在sessionStorage.image为undefined时才会触发,否则会直接读取sessionStorage中存储的值渲染。如果存储的图片链接有效,图片不会在模板中重新加载,直接瞬间渲染完成。
使用该方案不需要再单独写state = reactive的声明,直接全局使用store.state即可,也可以扩展关联sessionStorage或者localStorage,只需要维护store中的字段定义就行。如果不给state字段加空字符串默认值,Vue会抛出404 errors(不过因为响应式特性,等数据返回后元素最终还是会正常渲染)。
内容的提问来源于stack exchange,提问作者Artur Müller Romanov

