search
HomeWeb Front-endCSS TutorialHow to Make localStorage Reactive in Vue

Vue.js' responsive system is one of its core strengths, but it may feel mysterious to anyone who doesn't understand its underlying mechanisms. For example, why does it work with objects and arrays but not with other things like localStorage? This article will answer this question and demonstrate how to get Vue's responsive system to work with localStorage.

How to Make localStorage Reactive in Vue

If you run the following code, you will find that the counter is displayed as a static value and will not change as expected due to interval changes in localStorage:

 new Vue({
  el: "#counter",
  data: () => ({
    counter: localStorage.getItem("counter")
  }),
  computed: {
    Even() {
      return this.counter % 2 == 0;
    }
  },
  template: `<div>
    <div>Counter: {{ counter }}</div>
    <div>Counter is {{ even ? 'even' : 'odd' }}</div>
  </div>`
});
 // some-other-file.js
setInterval(() => {
  const counter = localStorage.getItem("counter");
  localStorage.setItem("counter", counter 1);
}, 1000);

Although counter property within the Vue instance is responsive, it does not change just because we changed its source in localStorage.

There are many ways to solve this problem, and the best way is probably to use Vuex and keep the stored values ​​synchronized with localStorage. But what if we just need a solution as simple as in this example? We must have an in-depth understanding of how Vue's responsive systems work.

Responsiveness in Vue

When Vue initializes a component instance, it observes data options. This means it will iterate over all properties in data and convert them to getter/setter using Object.defineProperty . By setting a custom setter for each property, Vue can know when the property changes and can notify dependencies that need to react to the change. How does it know which dependencies depend on a certain property? By leveraging getters, it can be registered when computed properties, observer functions, or rendering functions access data properties.

 // core/instance/state.js
function initData () {
  // ...
  observe(data)
}
 // core/observer/index.js
export function observe (value) {
  // ...
  new Observer(value)
  // ...
}

export class Observer {
  // ...
  constructor (value) {
    // ...
    this.walk(value)
  }

  walk (obj) {
    const keys = Object.keys(obj)
    for (let i = 0; i <p> So, why is localStorage not responsive? <strong>Because it is not an object with attributes.</strong></p><p> But wait. We can't define getters and setters with arrays, but in Vue, arrays are still responsive. This is because arrays are a special case in Vue. To have responsive arrays, Vue rewritten the array methods behind the scenes and integrated them with Vue's responsive system.</p><p> Can we do something similar to localStorage?</p><h3 id="Rewrite-localStorage-function"> Rewrite localStorage function</h3><p> First, we can fix our initial example by overriding the localStorage method to track which component instances requested the localStorage project.</p><p> // Map between localStorage project key and the list of Vue instances that depend on it const storeItemSubscribers = {};</p><p> const getItem = window.localStorage.getItem; localStorage.getItem = (key, target) => { console.info("Getting", key);</p><p> // Collect dependent Vue instances if (!storeItemSubscribers[key]) storeItemSubscribers[key] = []; if (target) storeItemSubscribers[key].push(target);</p><p> // Call the original function return getItem.call(localStorage, key); };</p><p> const setItem = window.localStorage.setItem; localStorage.setItem = (key, value) => { console.info("Setting", key, value);</p><p> // Update the value in the Vue instance that depends on if (storeItemSubscribers[key]) { storeItemSubscribers[key].forEach((dep) => { if (dep.hasOwnProperty(key)) dep[key] = value; }); }</p><p> // Call the original function setItem.call(localStorage, key, value); };</p><p> // ... (The rest of the code is the same as the original text)</p><p> In this example, we redefined <code>getItem</code> and <code>setItem</code> to collect and notify components that depend on localStorage projects. In the new <code>getItem</code> we record which component requests which item, and in <code>setItem</code> we contact all components that request the item and rewrite its data properties.</p><p> In order for the above code to work, we have to pass a reference to the component instance to <code>getItem</code> , which changes its function signature. We can't use the arrow function anymore, otherwise we won't have the correct value of <code>this</code> .</p><p> If we want to do better, we have to dig deeper. For example, how do we keep track of dependencies without explicitly passing them?</p><h3 id="How-to-collect-dependencies-in-Vue"> How to collect dependencies in Vue</h3><p> For inspiration, we can go back to Vue’s responsive system. We have seen before that when accessing a data property, the getter of the data property subscribes the caller to further changes to that property. But how does it know who made the call? When we get the data attribute, its getter function has no input about who the caller is. The Getter function has no input. How does it know who to register as a dependency?</p><p> Each data attribute maintains a list of its dependencies that need to react in a <code>Dep</code> class. If we dig deeper into this class, we can see that whenever a dependency is registered, the dependency itself is already defined in a static target variable. This goal is set by a mysterious <code>Watcher</code> class so far. In fact, when data properties change, these observers will be actually notified that they will initiate re-rendering of components or re-computing of computed properties.</p><p> But, again, who are they?</p><p> When Vue makes the data option observable, it also creates observers for each computed attribute function as well as all observation functions (which should not be confused with <code>Watcher</code> class) and the rendering function for each component instance. The observer is like a companion to these functions. They do two main things:</p><ol>
<li> <strong>They evaluate functions at creation time.</strong> This triggers the collection of dependencies.</li>
<li> <strong>When they are notified that the value they depend on has changed, they rerun their functions.</strong> This will eventually recalculate the computed properties or re-render the entire component.</li>
</ol><p> An important step occurs before the observer calls the functions they are responsible for: <strong>they set themselves as targets in static variables in <code>Dep</code> class.</strong> This ensures that when responsive data attributes are accessed, they are registered as dependencies.</p><h3 id="Track-who-called-localStorage"> Track who called localStorage</h3><p> We can't do this completely because we can't access Vue's internal mechanisms. However, we can use the idea of ​​Vue to let the observer set the target in a static property before calling the function it is responsible for. Can we set a reference to the component instance before calling localStorage?</p><p> If we assume that localStorage is called when setting data options, then we can hook to <code>beforeCreate</code> and <code>created</code> . These two hooks are fired before and after the initialization of the data option, so we can set it and then clear a target variable with a reference to the current component instance (we can access it in the lifecycle hook). Then, in our custom getter, we can register this target as a dependency.</p><p> The last thing we have to do is make these life cycle hooks a part of all our components. We can do this using global mixin for the entire project.</p><p> // ... (The rest of the code is the same as the original text)</p><p> Now, when we run the initial example, we will get a counter that increases the number per second.</p><p> // ... (The rest of the code is the same as the original text)</p><h3 id="The-end-of-our-thought-experiment"> The end of our thought experiment</h3><p> While we solved the initial problem, remember that this is mainly a thought experiment. It lacks some features, such as handling deleted projects and uninstalled component instances. It also has some limitations, such as the property name of the component instance needs to be the same as the project name stored in localStorage. That said, the main goal is to better understand how Vue responsive systems work behind the scenes and make the most of it, so I hope that's what you get from it all.</p>

The above is the detailed content of How to Make localStorage Reactive in Vue. For more information, please follow other related articles on the PHP Chinese website!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
The Slideout FooterThe Slideout FooterApr 09, 2025 am 11:50 AM

A fascinating new site called The Markup just launched. Tagline: Big Tech Is Watching You. We’re Watching Big Tech. Great work from Upstatement. The

Pages for LikesPages for LikesApr 09, 2025 am 11:47 AM

I posted about parsing an RSS feed in JavaScript the other day. I also posted about my RSS setup talking about how Feedbin is at the heart of it.

Recreating the CodePen Gutenberg Embed Block for Sanity.ioRecreating the CodePen Gutenberg Embed Block for Sanity.ioApr 09, 2025 am 11:43 AM

Learn how to create a custom CodePen block with a preview for Sanity Studio, inspired by Chris Coyier’s implementation for Wordpress’ Gutenberg editor.

How to Make a Line Chart With CSSHow to Make a Line Chart With CSSApr 09, 2025 am 11:36 AM

Line,  bar, and pie charts are the bread and butter of dashboards and are the basic components of any data visualization toolkit. Sure, you can use SVG

Programming Sass to Create Accessible Color CombinationsProgramming Sass to Create Accessible Color CombinationsApr 09, 2025 am 11:30 AM

We are always looking to make the web more accessible. Color contrast is just math, so Sass can help cover edge cases that designers might have missed.

How We Created a Static Site That Generates Tartan Patterns in SVGHow We Created a Static Site That Generates Tartan Patterns in SVGApr 09, 2025 am 11:29 AM

Tartan is a patterned cloth that’s typically associated with Scotland, particularly their fashionable kilts. On tartanify.com, we gathered over 5,000 tartan

A Follow-Up to PHP TemplatingA Follow-Up to PHP TemplatingApr 09, 2025 am 11:14 AM

Not long ago, I posted about PHP templating in just PHP (which is basically HEREDOC syntax). I'm literally using that technique for some super basic

Creating a Modal Image Gallery With Bootstrap ComponentsCreating a Modal Image Gallery With Bootstrap ComponentsApr 09, 2025 am 11:10 AM

Have you ever clicked on an image on a webpage that opens up a larger version of the image with navigation to view other photos?

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: How To Unlock Everything In MyRise
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

mPDF

mPDF

mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

SublimeText3 Linux new version

SublimeText3 Linux new version

SublimeText3 Linux latest version

MantisBT

MantisBT

Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.