I follow a number of web development related blogs and one of the blogs I like a lot is Go Make Things by Chris Fernandini. He posts very regularly and like me is not a fan of big frameworks and tooling with a lot of dependencies.

In one of his latest posts he shows how web components can share state with eachother and is using Custom DOM events to do that.  He uses an eCommerce based example with a Cart-link and a Cart-Item Web Component.

How would you share state between Web Components?
Yesterday, I had an interesting chat with a friend about how I would share state between Web Components, and get them to talk to each other in a web app.Today, let’s explore what that might look like!An ecommerce platform An example I like to use for this kind of thing is an ecommerce platform wit…

That got me thinking on how I would implement this usecase in Reken. It would also use components, but Reken based.

<template data-component="cart-link" data-arg-cart>
  <a href="/checkout" data-text="🛒 ${cart.size()} Items">
  </a>
</template>
Reken-based cart-link component definition

The cart-link component is a link to a checkout page. The link text displays the number of items in the cart based on the cart attribute.

<template data-component="product-listing" data-arg-uid data-arg-price data-arg-cart>
  <div>
    <em data-if="cart.has(uid)">This item is in your cart</em>
    <button data-if="!cart.has(uid)"
            data-action="cart.add(uid, price)">
            Add to Cart -
    		<span data-text="$${price}"></span>
    </button>
  </div>
</template>
Reken-based product-listing component definition

The product-listing component displays a product based on the uid and price attributes. It displays an Add to Card button when the product is not in the cart yet, but if it is already in the card it states so, instead of the button. The cart attribute is used to determine whether an item is already in the cart, and if not to add it to the cart.

To keep track of the cart state we create a cart class to has an add, has and a size method.

class Cart {
  constructor(val) {
    this.value = val || {};
  }

  add(key, val) {
    if (!key || val === undefined) return;
    this.value[key] = parseFloat(val);
  }

  size() {
    return Object.keys(this.value).length;
  }

  has(key) {
    return key && key in this.value;
  }
}
Cart class with value property keeping track of cart items and add, size and has function

We create a cart instance in the application state, based on the Cart class.

const app = {
  data: {
    cart: new Cart({}),
  }
}
application state object with the cart class instance

The main HTML code that displays the cart-link and product-listing looks as follows.

<cart-link cart="app.data.cart"></cart-link>
<product-listing cart="app.data.cart"
                 uid="tshirt-jolly-roger"
                 price="39">
</product-listing>
Display the cart-link and a product-listing

Now you may have noticed that the Reken based solution has two major differences with the solution Go Make Things provides.

  1. The Reken-based solution is based on Reken component definitions, as opposed to Web Components shown in the Go Make Things example.
  2. There are no events needed in the Reken based solution, as the Reken framework automically rerenders HTML when the application state is updated.

Here the full demo of the above presented Reken based solution.

Here an a slighty more eloborate Reken-based example, where we initialize the product list based on an array of products, and we can also empty and show to contents of the cart.