Table of Contents
Responsiveness in Vue
Rewrite localStorage function
How to collect dependencies in Vue
Track who called localStorage
The end of our thought experiment
Home Web Front-end CSS Tutorial How to Make localStorage Reactive in Vue

How to Make localStorage Reactive in Vue

Apr 04, 2025 am 10:16 AM

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>`
});
Copy after login
 // some-other-file.js
setInterval(() => {
  const counter = localStorage.getItem("counter");
  localStorage.setItem("counter", counter 1);
}, 1000);
Copy after login

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)
}
Copy after login
 // 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>
Copy after login

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 of this Website
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

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 ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: How To Unlock Everything In MyRise
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Working With GraphQL Caching Working With GraphQL Caching Mar 19, 2025 am 09:36 AM

If you’ve recently started working with GraphQL, or reviewed its pros and cons, you’ve no doubt heard things like “GraphQL doesn’t support caching” or

Making Your First Custom Svelte Transition Making Your First Custom Svelte Transition Mar 15, 2025 am 11:08 AM

The Svelte transition API provides a way to animate components when they enter or leave the document, including custom Svelte transitions.

Show, Don't Tell Show, Don't Tell Mar 16, 2025 am 11:49 AM

How much time do you spend designing the content presentation for your websites? When you write a new blog post or create a new page, are you thinking about

Building an Ethereum app using Redwood.js and Fauna Building an Ethereum app using Redwood.js and Fauna Mar 28, 2025 am 09:18 AM

With the recent climb of Bitcoin’s price over 20k $USD, and to it recently breaking 30k, I thought it’s worth taking a deep dive back into creating Ethereum

How do you use CSS to create text effects, such as text shadows and gradients? How do you use CSS to create text effects, such as text shadows and gradients? Mar 14, 2025 am 11:10 AM

The article discusses using CSS for text effects like shadows and gradients, optimizing them for performance, and enhancing user experience. It also lists resources for beginners.(159 characters)

What the Heck Are npm Commands? What the Heck Are npm Commands? Mar 15, 2025 am 11:36 AM

npm commands run various tasks for you, either as a one-off or a continuously running process for things like starting a server or compiling code.

Creating Your Own Bragdoc With Eleventy Creating Your Own Bragdoc With Eleventy Mar 18, 2025 am 11:23 AM

No matter what stage you’re at as a developer, the tasks we complete—whether big or small—make a huge impact in our personal and professional growth.

Let's use (X, X, X, X) for talking about specificity Let's use (X, X, X, X) for talking about specificity Mar 24, 2025 am 10:37 AM

I was just chatting with Eric Meyer the other day and I remembered an Eric Meyer story from my formative years. I wrote a blog post about CSS specificity, and

See all articles