Last updated: 01/21/2021
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
1) Use the mediator pattern. This is where the parent element mutates and feeds data to the child component.
Web components should be dumb. This means they do not own data, they only receive data, display data, and give data back.
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>
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');
})
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.
<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');
},
<time-picker
value="[[preferences.end_time)]]"
></time-picker>