Skip to content
Advertisement

Any way to make sessionStorage reactive in Vue3?

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).

Advertisement

Answer

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)
User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement