Lets say I built an app, that fetches data through axios.get
from a database every time it loads or is refreshed. This makes the app slow, so I want to only get the data in the initial load
of the app and put it into sessionStorage
.
Problem is that sessionStorage
is not reactive. When I do this:
const state = reactive({
image: sessionStorage.image
})
and want to render:
<div class="home-image" :style="{'background-image': 'url(' state.image ')'}"></div>
it only works, if the sessionStorage
has been updated in the previous page load. For the initial page load state.image
throws a 404 not found
.
Is there any way to make sessionStorage
reactive? I've read about watchers
, set
and get
but can't quite figure it out.
Solution (new):
Aaaaactually, I just found a way to make sessionStorage
behave as if it was reactive
during initial load
and I don't even need vuex
for it:
<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>
This way the reactive
function chooses an empty string, if sessionStorage
is undefined during the initial load and assigns value from axios.get
to sessionStorage
. On all consecutive page loads, the reactive
function uses sessionStorage
, which now has a value assigned to it.
Coding is fun. Sometimes you learn how to replace 100 lines of code with 1 LOC.
Solution (old):
Ok, now my storage works how I want it to. It is global
, reactive
, persistent
and easy to use. I will accept @Elsa's answer because she helped me look into vuex
.
I created a store
in a seperate store.js
file:
import {createStore} from "vuex";
const store = createStore({
state() {
return {
image: sessionStorage.image || ""
}
}
})
export default store
then register it in app.js
:
require('./bootstrap');
import {createApp} from 'vue';
import app from "../vue/app";
import store from "./store";
createApp(app)
.use(store)
.mount("#app");
and now I can use store
in my components like so:
<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>
The axios
request runs only if sessionStorage.image
is undefined, otherwise its value is rendered directly. If the link exists, the image does not get newly loaded in the template first, but rendered instantly.
I might omit state = reactive
completely now, since I can use store.state
instead globally and even link it to ss/ls
. The only thing I have to maintain is the fields inside:
const store = createStore({
state() {
return {
image: sessionStorage.image || ""
}
}
})
because vue
throws 404 errors
if I don't (but renders the elements anyway because of reactivity).
CodePudding user response:
I had this problem a week ago and I try 3 ways to make a sessionStorage reactive in vue3. 1.vuex 2.create event listener 3.setInterval
I found a temporary solution for my problem with setInterval.
1.vuex
const state = () => {
return {
latInfo: sessionStorage.getItem('lat') || 0
}
}
const getters = {
latInfo: state => state.latInfo
}
3.setInterval
setup() {
setInterval(() => {
if (infoData) {
infoData.lat = sessionStorage.getItem('lat')
}
}, 1000)
CodePudding user response:
Firstly, sessionStorage cannot be reactive.
If my understanding correct, you just want a global variable to be reactive. You can simply achieve it via provide and inject:
const yourGlobalVar = sessionStorage.getItem('image');
app.provide('yourImage', ref(yourGlobalVar))
Where used it:
setup(){
...
const image = inject('yourImage');
...
return {image}
}