Skip to content

Instantly share code, notes, and snippets.

@dman777
Last active January 21, 2021 23:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dman777/138db668efbc1d929118c53dc8b236fc to your computer and use it in GitHub Desktop.
Save dman777/138db668efbc1d929118c53dc8b236fc to your computer and use it in GitHub Desktop.
architecture for web components

Last updated: 01/21/2021

Best practices for web components

These tips came from Google's Polymer team, the originator and creator of web components. These patterns and architecture can be applied to any re-usable component regardless if it's a true webcomponent or not.

Videos:

Data Flow in Polymer Elements - mediator pattern

Chrome Dev Summit - unidirectional data flow

Architecture for web components: 

1)  Use the mediator pattern. This is where the parent element mutates and feeds data to the child component. 

Who owns the data? 

Web components should be dumb. This means they do not own data, they only receive data, display data, and give data back.

bad

The component consumes the api and owns the data. Many apps will use the component. A single App that use this component may need unqiue functionality on how the data is displayed that the other apps do not require. The end result is modifying the component for one off behaviors resulting in a bloated code base.

<parent-element>
  <car-inventory-table
     api-url="/cars"
     filter="hondas"
  ></car-inventory-table>
</parent-element>
good

Here, the parent consumes the cars api and owns the data. Any unqiue behavior that would only be specific to this particular app can be done outside of the component. The car-invetory-table is a now a dumb element. It doesn't own the data, mutate the data, or care what should happen to the data. It's job is to display the data it is given.

This keeps car-inventory-table portable (compatible with many apps). It also allows for a non bloated code base that is easier to maintain and with less bugs.

<parent-element>
  <car-inventory-table
   items="carList"
  ></car-inventory-table>
</parent-element>
parentElement code:

fetch('/cars')
  .then((res) => res.json())
  .then((cars) => {
    this.carList = cars.filter((car) => car.maker !== 'honda');
  })
Data Flow

Do not use 2 way bindings, memory references, or mutate memory.

  • Downward data (from parent to child) - use one way bindings

  • Upward data (from child to parent) - use events

This will keep source data pure (ie pre-existing data on forms) and more predictable without side effects. This will also allow less code in your component where you will not have to observe objects changing and dealing with null values on ever changing objects and properties.

good
<time-picker
  on-time-changed="_setModifiedTime"
  value="[[_setTime(preferences.end_time)]]"
></time-picker>
_setModifiedTime: function(e) { 
  this.customPreferences.provide_end_time = e.detail.timeString;
  this._setDirty();
},

_setTime: function(e) { 
  return moment(e, 'hh:mm A').format('hh:mm A');
},
bad
<time-picker
  value="[[preferences.end_time)]]"
></time-picker>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment