Ad/iklan :






Search.Pencarian Menu

Add text send email to rh3252705.adda@blogger.com or Click this (Text porn Will delete) | Tambah teks kirim email ke rh3252705.adda@blogger.com atau Klik ini (Teks porno akan dihapus)
Total post.pos : 12621+

[Go Make Things] Creating a vanilla JavaScript signal() with Proxies

Yesterday, we looked at vanilla JS Proxies.

Today, I wanted to show you how you can use them to create reactive signals. Let's dig in!

An example

Let's imagine you have a cart object ({}).

let cart = {};  

Whenever it's updated, you have code in multiple different places that needs to know it's been changed, know what changed, and run some actions in response.

// When this happens, some other code should automatically run in response  cart.shirt = {  	size: 'medium',  	quantity: 1  };  

Proxies are perfect for this!

This is actually how libraries like Vue work under-the-hood. If you want to learn more about that, I do a deep-dive into state-based UI over at the Lean Web Club.

Creating a signal() function using Proxies

First, let's create a signal() function that accepts a data value to create a Proxy from.

We'll use a plain object ({}) as the default value if none is provided. We also want each signal object to have a unique name or identifier. We'll pass in a name variable for that.

function signal (data = {}, name = '') {  	// ...  }  

Next, let's create a handler() function that returns our handler object. We'll do this to handle nested arrays and objects.

function signal (data = {}, name = '') {    	/**  	 * Create a Proxy handler object  	 * @param  {Object} data The data object  	 * @param  {String} name The signal name  	 * @return {Object}      The handler object  	 */  	function handler (data, name) {  		return {  			get (obj, prop) {  				if (key === '_isProxy') return true;  				let nested = ['[object Object]', '[object Array]'];  				let type = Object.prototype.toString.call(obj[key]);  				if (nested.includes(type) && !obj[key]._isProxy) {  					obj[prop] = new Proxy(obj[prop], handler(name, data));  				}  				return obj[prop];  			},  			set (obj, prop, value) {  				if (obj[prop] === value) return true;  				obj[prop] = value;  				return true;  			},  			deleteProperty (obj, prop) {  				delete obj[prop];  				return true;  			}  		};  	}    }  

Now, we can create and return a new Proxy().

function signal (data = {}, name = '') {    	// ...    	// Create a new Proxy  	return new Proxy(data, handler(data, name));    }  

Emitting a custom event

Let's add an emit() function to our signal() function that emits a custom event.

Quick aside: you can find this and lots of other helper functions like it over at the Lean Web Club.

We'll pass in the signal name, as well as a detail object with details about what changed.

/**   * Emit a custom event   * @param  {String} name   The unique name for the signal   * @param  {*}      detail Any details to pass along with the event   */  function emit (name, detail = {}) {    	// Create a new event  	let event = new CustomEvent(`signal:${name}`, {  		bubbles: true,  		detail: detail  	});    	// Dispatch the event  	return document.dispatchEvent(event);    }  

Now, in our handler(), we can emit() events when data is set or deleted.

For details, we'll include the prop that was changed, it's value, and an action indicating how it changed.

/**   * Create a Proxy handler object   * @param  {Object} data The data object   * @param  {String} name The signal name   * @return {Object}      The handler object   */  function handler (data, name) {  	return {  		get (obj, prop) {  			if (key === '_isProxy') return true;  			let nested = ['[object Object]', '[object Array]'];  			let type = Object.prototype.toString.call(obj[key]);  			if (nested.includes(type) && !obj[key]._isProxy) {  				obj[prop] = new Proxy(obj[prop], handler(name, data));  			}  			return obj[prop];  		},  		set (obj, prop, value) {  			if (obj[prop] === value) return true;  			obj[prop] = value;  			emit(name, {prop, value, action: 'set'});  			return true;  		},  		deleteProperty (obj, prop) {  			delete obj[prop];  			emit(name, {prop, value: obj[prop], action: 'delete'});  			return true;  		}  	};  }  

Using a signal()

Now, we can create a cart object as a signal(), like this…

let cart = signal({}, 'cart');  

We can listen for changes it to it like this…

document.addEventListener('signal:cart', function (event) {  	console.log(event.detail);  });  

And whenever we update our cart, an event will fire off.

cart.shirt = {  	size: 'medium',  	quantity: 1  };    cart.pants = {  	size: 32,  	quantity: 2  };    delete cart.pants;  

Here's a demo.

Join the Lean Web Club! Coaching. Courses. Coding resources. Get the skills, confidence, and support you need to learn front-end web development and achieve long-term success.

Cheers,
Chris

Want to share this with others or read it later? View it in a browser.

Share :

Facebook Twitter Google+
0 Komentar untuk "[Go Make Things] Creating a vanilla JavaScript signal() with Proxies"

Back To Top