最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Any way to make sessionStorage reactive in Vue3? - Stack Overflow

programmeradmin0浏览0评论

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

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

Share Improve this question edited Nov 1, 2021 at 14:53 Artur Müller Romanov asked Oct 31, 2021 at 17:58 Artur Müller RomanovArtur Müller Romanov 5,90120 gold badges110 silver badges192 bronze badges 3
  • 2 No, you can't make sessionStorage reactive in that way. But, this is quite literally the use case for Vuex! – Brother Woodrow Commented Oct 31, 2021 at 18:39
  • Why not using the provide and inject? – huan feng Commented Nov 1, 2021 at 7:48
  • @huanfeng I'd prefer using a global reactive storage instead – Artur Müller Romanov Commented Nov 1, 2021 at 8:08
Add a ment  | 

3 Answers 3

Reset to default 2

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)

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}
}

VueUse is doing it, take a look at useStorage() method

发布评论

评论列表(0)

  1. 暂无评论