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

javascript - How to make data from localStorage reactive in Vue js - Stack Overflow

programmeradmin4浏览0评论

I am using localStorage as a data source in a Vue js project. I can read and write but cannot find a way to use it reactively. I need to refresh to see any changes I've made.

I'm using the data as props for multiple components, and when I write to localStorage from the components I trigger a forceUpdate on the main App.vue file using the updateData method.

Force update is not working here. Any ideas to accomplish this without a page refresh?

...............
data: function () {
        return {
            dataHasLoaded: false,
            myData: '',
        }
    },
mounted() {
        const localData = JSON.parse(localStorage.getItem('myData'));
        const dataLength = Object.keys(localData).length > 0;
        this.dataHasLoaded =  dataLength;
        this.myData = localData;
    },
methods: {
    updateData(checkData) {
        this.$forceUpdate();
        console.log('forceUpdate on App.vue')
    },
},
...............

I am using localStorage as a data source in a Vue js project. I can read and write but cannot find a way to use it reactively. I need to refresh to see any changes I've made.

I'm using the data as props for multiple components, and when I write to localStorage from the components I trigger a forceUpdate on the main App.vue file using the updateData method.

Force update is not working here. Any ideas to accomplish this without a page refresh?

...............
data: function () {
        return {
            dataHasLoaded: false,
            myData: '',
        }
    },
mounted() {
        const localData = JSON.parse(localStorage.getItem('myData'));
        const dataLength = Object.keys(localData).length > 0;
        this.dataHasLoaded =  dataLength;
        this.myData = localData;
    },
methods: {
    updateData(checkData) {
        this.$forceUpdate();
        console.log('forceUpdate on App.vue')
    },
},
...............
Share Improve this question edited Feb 14, 2023 at 5:12 spinkus 8,5504 gold badges44 silver badges72 bronze badges asked Jun 25, 2018 at 0:53 UXCODAUXCODA 1,2262 gold badges22 silver badges34 bronze badges 9
  • this.clientFirstName = assumes you have a clientFirstName: '' somewhere in your data: return { clientFirstName: '', dataHasLoaded: false, myData: '' } – ippi Commented Jun 25, 2018 at 0:58
  • Yes, sorry I forgot to omit that. I'll edit now. Thanks – UXCODA Commented Jun 25, 2018 at 1:01
  • You should not need a $forceUpdate here. Maybe show us how you save the data? If you type in localStorage.getItem('myData') in your javascript console (on the app page), do you get output (other than null)? – ippi Commented Jun 25, 2018 at 1:04
  • Hi, Yes everything is working, I can read from and write to localStorage but I cannot see the changes on the screen without refreshing the page. I need to force Vue to re-read the data when I've updated it to see the latets changes on the screen. – UXCODA Commented Jun 25, 2018 at 1:07
  • jsfiddle.net/ippi/fd35but8/5 I'm trying to reproduce your problem, and I can see you need something to detect a localStorage change (sending some event, using a event bus, setting a state with vuex, etc), but I can't see any reactivity problems from vue's side. – ippi Commented Jun 25, 2018 at 1:53
 |  Show 4 more comments

4 Answers 4

Reset to default 13

Here's how I solved this. Local storage just isn't reactive, but it is great for persisting state across refreshes.

What is great at being reactive are regular old data values, which can be initialized with localStorage values. Use a combination of a data values and local storage.

Let's say I was trying to see updates to a token I was keeping in localStorage as they happened, it could look like this:

const thing = new Vue({
  data(){
    return {
      tokenValue: localStorage.getItem('id_token') || '',
      userValue: JSON.parse(localStorage.getItem('user')) || {},
    };
  },
  computed: {
    token: {
      get: function() {
        return this.tokenValue;
      },
      set: function(id_token) {
        this.tokenValue = id_token;
        localStorage.setItem('id_token', id_token)
      }
    },
    user: {
      get: function() {
        return this.userValue;
      },
      set: function(user) {
        this.userValue = user;
        localStorage.setItem('user', JSON.stringify(user))
      }
    }
  }
});

The problem initially is I was trying to use localStorage.getItem() from my computed getters, but Vue just doesn't know about what's going on in local storage, and it's silly to focus on making it reactive when there's other options. The trick is to initially get from local storage, and continually update your local storage values as changes happen, but maintain a reactive value that Vue knows about.

For anyone facing the same dilemma, I wasn't able to solve it the way that I wanted but I found a way around it.

  • I originally loaded the data in localStorage to a value in the Parent's Data called myData.
  • Then I used myData in props to populate the data in components via props.
  • When I wanted to add new or edit data,
    • I pulled up a fresh copy of the localStorage,
    • added to it and saved it again,
    • at the same time I emit the updated copy of localStorage to myData in the parent,
    • which in turn updated all the data in the child components via the props.

This works well, making all the data update in real time from the one data source.

Ryan's answer works perfectly but I wanted to share it is also possible to use watch to up keep the local storage in sync with a ref:

const token = ref(localStorage.getItem('token') || undefined)
watch(token, newValue => {
    if (!newValue) localStorage.removeItem('token')
    else localStorage.setItem('token', newValue)
})

As items in localstorage may be updated by something else than the currently visible vue template, I wanted that updating function to emit a change, which vue can react to.

My localstorage.set there does this after updating the database:

    window.dispatchEvent(new CustomEvent('storage-changed', {
        detail: {
            action: 'set',
            key: key,
            content: content
        }
    }));

and in mounted() I have a listener which updates forceRedraw, which - wait for it - force a redraw.

    window.addEventListener('storage-changed', (data) => {
        this.forceRedraw++;
        ...
发布评论

评论列表(0)

  1. 暂无评论