<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: hybrids</title>
    <description>The latest articles on DEV Community by hybrids (@hybrids).</description>
    <link>https://dev.to/hybrids</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1991%2F4075a9b6-6447-4659-a635-43318ef9f5b3.png</url>
      <title>DEV Community: hybrids</title>
      <link>https://dev.to/hybrids</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hybrids"/>
    <language>en</language>
    <item>
      <title>Three unique features of the hybrids template engine that you must know</title>
      <dc:creator>Dominik Lubański</dc:creator>
      <pubDate>Thu, 19 Dec 2019 17:12:06 +0000</pubDate>
      <link>https://dev.to/hybrids/three-unique-features-of-the-hybrids-template-engine-that-you-must-know-5ada</link>
      <guid>https://dev.to/hybrids/three-unique-features-of-the-hybrids-template-engine-that-you-must-know-5ada</guid>
      <description>&lt;p&gt;For all of you who don't know yet, &lt;a href="https://hybrids.js.org/"&gt;hybrids&lt;/a&gt; is a JavaScript library for creating web components. It uses a unique hybrid approach based on plain objects and pure functions. This article is the fourth in the series about the core features of the library.&lt;/p&gt;

&lt;p&gt;So far we covered how to give up on classes and switch to the full power of plain objects. We have learned more about the cache mechanism, and we have discovered how the latest changes made the library even faster and easier to use. &lt;/p&gt;

&lt;p&gt;However, let's be honest - the templates are the heart of UI components. Also, they usually take the biggest part of the component definition. In hybrids, you've got the ultimate freedom to choose the tool for this job. It's super easy to adopt any UI library, that produces the DOM and use it with render factory as a template engine (here you have two examples using &lt;a href="https://stackblitz.com/edit/hybrids-react-counter?file=react-counter.js"&gt;React&lt;/a&gt; and &lt;a href="https://stackblitz.com/edit/hybrids-lit-html-counter?file=lit-counter.js"&gt;lit-html&lt;/a&gt;). However, the built-in template engine can give you important benefits over the other options.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspiration
&lt;/h2&gt;

&lt;p&gt;The foremost inspiration for the built-in template engine was the &lt;a href="https://lit-html.polymer-project.org/"&gt;lit-html&lt;/a&gt; library, but the implementation is different and it follows its own conventions. The main objective was to use tagged template literals syntax to create the DOM and update dynamic parts leaving static content untouched.&lt;/p&gt;

&lt;p&gt;At the time when the engine was created the lit-html was in the very early development stage. After the first major version, the syntax has changed dramatically. I wanted to create a library, which has no external dependencies, so there will be no problem with possible breaking changes. Also, the hybrids library brings some unique patterns, which I knew that the template engine should follow. For these reasons, I decided to try to build it myself. What we can say about the result?&lt;/p&gt;

&lt;h2&gt;
  
  
  Closest to the roots
&lt;/h2&gt;

&lt;p&gt;One of the main differences is how it tries to predict user needs, so you don't have to learn special DSL or additional syntax for passing properties or attaching event listeners - just use pure HTML and expressions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
  &amp;lt;button onclick="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;increaseCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" disabled="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;
    Count: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
  &amp;lt;/button&amp;gt;
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The built-in elements follow the pattern, where attributes are reflected with corresponding property values. The &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; element goes even further and its &lt;code&gt;value&lt;/code&gt; can be updated only by the property. The template engine uses element definition and chooses if it should pass values to the property, or eventually use the attribute (as a fallback when the property is not found in the prototype chain). Event listeners are attached by the &lt;code&gt;on*&lt;/code&gt; attributes, where the second part is used as the type of the event. Even though attributes are not case-sensitive, the template engine uses the exact name defined in the template, so it is possible to set properties like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
  &amp;lt;div innerHTML="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;mySafeHTML&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" onMyCustom-event="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;myListener&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;&amp;lt;/div&amp;gt;
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There are two exceptions for the built-ins - &lt;code&gt;class&lt;/code&gt; and &lt;code&gt;style&lt;/code&gt; attributes. As they reflect different properties, the engine accepts a variety of values passed to expressions and it passes them to the right DOM APIs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
  &amp;lt;button class="&lt;/span&gt;&lt;span class="p"&gt;${{&lt;/span&gt; &lt;span class="nl"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;}"&amp;gt;...&amp;lt;/button&amp;gt;
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You may think, that it can't work for all complicated use cases, but give it a try - after all the templates are just about elements composition, passing data and receiving feedback by event listeners!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A deeper explanation of the concept can be found in the &lt;a href="https://hybrids.js.org/template-engine/properties-and-attributes"&gt;Properties &amp;amp; Attributes&lt;/a&gt; section of the hybrids library documentation.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let the host be with you
&lt;/h2&gt;

&lt;p&gt;The most unique feature is related to one of the core patterns of the hybrids library. Instead of using &lt;code&gt;this&lt;/code&gt; syntax, the descriptors' methods take a host element as a first argument. This simple shift has a great impact on data flow. The definition of the function is decoupled from the execution context, so those methods are pure functions (except obvious template side effects). A similar idea was implemented in the template engine.&lt;/p&gt;

&lt;p&gt;The render factory requires that the passed function will return &lt;code&gt;UpdateFunction(host, target)&lt;/code&gt;, which takes two arguments - the host and target element. The template engine &lt;code&gt;html&lt;/code&gt; not only produces an &lt;code&gt;UpdateFunction&lt;/code&gt; but also supports it as a nested template used in the expression. It will be clearer if we look at the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// We still have access to DOM `event` in the second argument&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Did it!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Do it!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
    &amp;lt;div id="content"&amp;gt;
      &amp;lt;button onclick="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Because the result of the template engine has access to the host element, we can use it for event listeners. Instead of passing only the event object, the first argument is the host. Do you see how this makes a huge difference? The user actions usually change the state of the component, not the element, with which the interaction was taken. &lt;/p&gt;

&lt;p&gt;If we would not have direct access to the host element, we would have to create a dynamic function inside of the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Do it!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
      &amp;lt;div id="content"&amp;gt;
        &amp;lt;button onclick="&lt;/span&gt;&lt;span class="p"&gt;${()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Did it!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;
    `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the above example, we no longer can use destructuring at the level of the arguments - we need a reference to the host. Also, the side effect became an internal part of the template. &lt;/p&gt;

&lt;p&gt;It has two important implications. The function will be generated each time the template updates. Also, unit testing is much harder. Before, with access to the host, it was possible to write simple unit tests for the &lt;code&gt;doSomething()&lt;/code&gt; function. It wasn't linked to the template at all nor to DOM elements - it was just a function, which takes an object and updates its &lt;code&gt;name&lt;/code&gt; property. It's not possible with the callback defined inside of the template.&lt;/p&gt;

&lt;p&gt;What about the nested templates? The expressions support passing &lt;code&gt;UpdateFuncion&lt;/code&gt;, which &lt;code&gt;html&lt;/code&gt; returns. Because of that, it's possible to create separate functions producing partial templates, even outside of the main component definition. If they use event listeners, the callbacks will still have the correct access to the component host element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// It can be safely defined in a separate file, like `partials.js`&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;buttonPartial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
    &amp;lt;button onclick="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/button&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// And then imported&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;buttonPartial&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./partials&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// It still works, as the host is what we expect to be&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Yes, you did it!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Do it!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
    &amp;lt;div&amp;gt;
      ...
      &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;buttonPartial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;
    &amp;lt;/div&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;buttonPartial()&lt;/code&gt; function adapts to the place where it is used - so no matter in which component definition you will use it, the passed callback for a click event can run side effects related to the component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Helper methods
&lt;/h2&gt;

&lt;p&gt;At last but not least, I would like to share with you yet another unique approach. The template engine includes helper methods for setting the unique key of the template, dynamically defining web components and passing text-based styles.&lt;/p&gt;

&lt;p&gt;The first one - &lt;code&gt;key(id)&lt;/code&gt; - allows efficient re-order elements of the array. The &lt;code&gt;lit-html&lt;/code&gt; requires using &lt;code&gt;repeat()&lt;/code&gt; directive if we want to notify the library about items identifiers. Here you have &lt;a href="https://lit-html.polymer-project.org/guide/writing-templates#repeating-templates"&gt;an example&lt;/a&gt; from its documentation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;employeeList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
  &amp;lt;ul&amp;gt;
    &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;employee&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;employee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;employee&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
      &amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;employee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;familyName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;employee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;givenName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/li&amp;gt;
    `&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;
  &amp;lt;/ul&amp;gt;
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And this is an explanation of the feature:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In most cases, using loops or &lt;code&gt;Array.map&lt;/code&gt; is an efficient way to build repeating templates. However, if you want to reorder a large list, or mutate it by adding and removing individual entries, this approach can involve recreating a large number of DOM nodes.&lt;/p&gt;

&lt;p&gt;The repeat directive can help here. Directives are special functions that provide extra control over rendering. lit-html comes with some built-in directives like &lt;code&gt;repeat&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Isn't cooler in hybrids, that if you want to hold generated templates in the DOM, all you have to do is to add &lt;code&gt;.key()&lt;/code&gt; at the end of the &lt;code&gt;html&lt;/code&gt; call? Let's try to write the above example with the hybrids template engine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;employeeList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
  &amp;lt;ul&amp;gt;
    &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;familyName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;givenName&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
      &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;familyName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;givenName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/li&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;
  &amp;lt;/ul&amp;gt;
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;define()&lt;/code&gt; helper allows bootstrapping only the required elements and creating a tree-like dependency structure. With usage of this helper, a complex structure of elements may require only one explicit definition at the root level. In the following example, the &lt;code&gt;UiHeader&lt;/code&gt; will be defined once the &lt;code&gt;withHeader&lt;/code&gt; flag is turned on for the first time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;UiHeader&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./UiHeader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UiCard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;withHeader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;withHeader&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
    &amp;lt;div&amp;gt;
      &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;withHeader&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
        &amp;lt;ui-header&amp;gt;...&amp;lt;/ui-header&amp;gt;
      `&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;UiHeader&lt;/span&gt; &lt;span class="p"&gt;})}&lt;/span&gt;&lt;span class="s2"&gt;
      ...
    &amp;lt;/div&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you are going to use external CSS files for your project, the &lt;code&gt;style()&lt;/code&gt; helper is what you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// `styles` should contain text content of CSS file&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./MyElement.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
    &amp;lt;div&amp;gt;...&amp;lt;/div&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;A deeper explanation of how to use template helpers can be found in the &lt;a href="https://hybrids.js.org/template-engine/iteration"&gt;Iteration&lt;/a&gt;, &lt;a href="https://hybrids.js.org/template-engine/dependencies"&gt;Dependencies&lt;/a&gt; and &lt;a href="https://hybrids.js.org/template-engine/styling"&gt;Styling&lt;/a&gt; section of the hybrids library documentation.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Those three features of the template engine that you get for free with the hybrids library show how little differences can make a huge impact on how we write code. The lit-html was created as a general-purpose rendering library, so some of the ideas presented here don't fit. However, in hybrids, the goal is one - make the best possible experience in building web components.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;Through the last articles, we have learned the main concepts, which apply to factories provided by the library. Let's take a closer look at them to know how to use their powers. One of those used mainly behind the scenes is the &lt;code&gt;property&lt;/code&gt; factory (using translation feature). What happens when you define a property as a simple primitive value or complex object? We will find out with the next article from the series!&lt;/p&gt;

&lt;p&gt;In the meantime, you can read more about the library at the &lt;a href="https://hybrids.js.org"&gt;project documentation&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;🙏 &lt;strong&gt;How can you support the project?&lt;/strong&gt; Give the GitHub repository a ⭐️, comment below ⬇️ and spread the news about hybrids to the world 📢!&lt;/p&gt;




&lt;p&gt;&lt;small&gt;Cover photo by &lt;a href="https://unsplash.com/photos/ZsvuETrThX8"&gt;Kelly Sikkema&lt;/a&gt; on &lt;a href="https://unsplash.com"&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>webcomponents</category>
      <category>functional</category>
    </item>
    <item>
      <title>Chasing the best performance of rendering the DOM by hybrids library</title>
      <dc:creator>Dominik Lubański</dc:creator>
      <pubDate>Sat, 01 Jun 2019 14:34:40 +0000</pubDate>
      <link>https://dev.to/hybrids/chasing-the-best-performance-of-rendering-the-dom-by-hybrids-library-436d</link>
      <guid>https://dev.to/hybrids/chasing-the-best-performance-of-rendering-the-dom-by-hybrids-library-436d</guid>
      <description>&lt;p&gt;&lt;em&gt;This is the third in a series of posts about core concepts of &lt;a href="https://github.com/hybridsjs/hybrids" rel="noopener noreferrer"&gt;hybrids&lt;/a&gt; - a library for creating Web Components from plain objects and pure functions.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It's been a while since the last post of the series. Let's catch up on what we have learned so far. The first post explained how the hybrids made web components definition possible without &lt;code&gt;class&lt;/code&gt; and &lt;code&gt;this&lt;/code&gt; syntax, but with a truly composable structure with pure functions. The second post described built-in cache and change detection mechanisms, which hide redundant lifecycle methods and keep data in sync in a declarative way. If you haven't read them yet, this is the moment to make up for it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/smalluban/from-classes-to-plain-objects-and-pure-functions-2gip"&gt;From classes to plain objects and pure functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/smalluban/how-to-say-goodbye-to-lifecycle-methods-and-focus-on-productive-code-175"&gt;Say goodbye to lifecycle methods, and focus on productive code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Finally, we can focus on one of the most critical features of all UI libraries - creating and updating the DOM. I think it is not a surprise that hybrids implements this feature slightly different than most libraries and frameworks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Render is just yet another factory&lt;/strong&gt;. The foundation of hybrids is the property descriptor concept. Instead of creating a separate internal structure, the library provides render feature as one of the built-in property factories. It brings important benefits. For example, you are not forced to use it. If a built-in solution does not match your needs, you can create a custom render factory, or define local descriptor, which renders and updates the DOM. Moreover, all specific features built for this purpose are available for other definitions. They are part of the public API.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Render factory is a template engine agnostic&lt;/strong&gt;. Most of the projects force users to use the template solution chosen by the authors. Sometimes it is even impossible to use another one. It might look right - after all, this is considered to be the main objective of the UI libraries. However, I believe that it is always better to have a choice. Of course, hybrids render factory works out of the box with a built-in template engine, but you can easily replace it with React, lit-html or your favorite UI library (The only constraint is that it has to create and update the DOM).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;You will always have the fastest solution&lt;/strong&gt;. Whether you decide to use render factory or not, and whatever template engine you apply - you will still benefit from the hybrids foundations. The cache will prevent redundant calculations, while the change detection mechanism will schedule updates at the end of the next frame in the browser.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I could list many other advantages, but let's face it - rendering the DOM it's all about performance! How does it apply to hybrids? Even though being the fastest rendering library was never the primary goal, from the very beginning hybrids has provided performant DOM rendering. However, recent updates in the project show that some concepts had to be polished. I would like to share with you how I get to those changes, and how they helped hybrids be able to chase the performance of the fastest libraries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trigger for investigation
&lt;/h3&gt;

&lt;p&gt;Last December, Vincent Ogloblinsky wrote to me about &lt;a href="https://vogloblinsky.github.io/web-components-benchmark/" rel="noopener noreferrer"&gt;Web Components Benchmark&lt;/a&gt; project. He has created two suites of tests measuring the performance of the web components UI libraries, as well as some mainstream frameworks. Thank you, Vincent, for adding hybrids to your project! &lt;/p&gt;

&lt;p&gt;If you would look at the results of the Todo List test, hybrids was somewhere in the middle. The stress test result was more disturbing (the test is about rendering thousands of elements of the Pascal Triangle, which has one hundred rows). The vanilla implementation was below 3 seconds. What about hybrids? It was more than 10 seconds! I thought that implementation might be wrong, but after a closer look, it became clear that some of my assumptions were wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recursion
&lt;/h3&gt;

&lt;p&gt;When I run the Pascal Triangle test on my local machine, the first thing I noticed was an error message in the console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Uncaught RangeError: Maximum call stack size exceeded
    at WeakMap.get (&amp;lt;anonymous&amp;gt;)
    at c (render.js:20)
    at c (render.js:30)
    at c (render.js:30)
    at c (render.js:30)
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ups... The render factory was using recursion in the update process. As long as a list of elements to render was lower than the call stack limit of the JavaScript engine (for V8 it is about 10k), everything worked. However, for one hundred rows, it blew up. I checked, and the safe number is 95. It was very close to not discover the problem!&lt;/p&gt;

&lt;p&gt;By the way, the score of the test was even better than it should, as computation stopped before the end of the queue. &lt;/p&gt;

&lt;p&gt;The obvious solution is to replace recursion with iteration, where you hold and replace the current item in the variable instead of calling the same function on the end of the loop. The same computation using iteration is also much faster than with recursion.&lt;/p&gt;

&lt;h3&gt;
  
  
  DOM Events
&lt;/h3&gt;

&lt;p&gt;The second discovered problem was the change detection mechanism. It was built on top of the DOM events. I thought that using them is the right decision. After all, the library is about HTML elements, and they have built-in support for listening and dispatching events. Why should we create a custom structure if we can use "the platform"?&lt;/p&gt;

&lt;p&gt;However, I missed one crucial fact - dispatching events can take half of the time of the rendering process if there are many elements there. Take a look at the fragment of Chrome Dev Tools performance chart:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyd7k7j8bprrhfffwbxs0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyd7k7j8bprrhfffwbxs0.png" alt="Chrome Dev Tools Performance Chart for Pascal Triangle Test" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When Pascal Triangle items are connected for the first time, they dispatch the DOM event to trigger their render process (controlled by change detection mechanism). This event is listened by render property of the element, which eventually triggers an update of the DOM of the item.  More or less dispatching events takes the same amount of time as putting them in the document. However, if you look at the chart again, you can see another thing - the update process is split between several animation frames after the initial render.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multiple calls to &lt;code&gt;requestAnimationFrame&lt;/code&gt; API
&lt;/h3&gt;

&lt;p&gt;In the time when I was rapidly developing hybrids, the asynchronous rendering of the React Fabric was a hot topic. Creating not blocking user input rendering was a tempting idea. And I deemed it's quite easy to implement. The render factory was already using &lt;code&gt;requestAnimationFrame&lt;/code&gt; API to schedule the update. The only thing which I had to add was to split the work if the update lasted too long.&lt;/p&gt;

&lt;p&gt;We always dream of 60 FPS, so without thinking twice, I set ~16ms budget. After the threshold, the rest of the work was done in the next animation frame (within the own ~16ms budget). No user input blocking, updates in the middle of rendering... It seems to be the holy grail... but it isn't.  After each animation frame, the browser has to do a lot of work - recalculate styles, compose the layout, update layer tree, and eventually paint all of that on the screen. Simple structures of elements rarely hit the threshold. If your structure is massive on another hand - the sum of separated executions between frames will always be higher than done in a single one. But without it we might block user input for a long time, don't we?&lt;/p&gt;

&lt;h3&gt;
  
  
  To make it faster just do less
&lt;/h3&gt;

&lt;p&gt;The above statement seems to be the obvious truth. But authors of some libraries claimed in the past that JavaScript is fast enough - the only problem is the DOM. However, studying performance charts of the Pascal Triangle test taught me, that every variable, call to function or iteration has a cost. We can't avoid some of the work, but functions can be less, data structures can be more straightforward, and iterations might be reduced or scheduled smarter.&lt;/p&gt;

&lt;h3&gt;
  
  
  The results
&lt;/h3&gt;

&lt;p&gt;On the 29th of May, hybrids hit a new major version, with significant performance improvements. The change detection mechanism has been redesigned. Scheduler, which was an internal part of the render factory is now available for all descriptors. Also, it does not use recursion in the implementation. Instead of attaching and removing event listeners, you should use &lt;code&gt;observe&lt;/code&gt; method. It's called in the property scope and only if the property value has changed (it also tracks all dependencies and notify if they change). The callback is queued with &lt;code&gt;requestAnimationFrame&lt;/code&gt; API but without the threshold. In the result render factory is now implemented within 30 lines of code. The rest is now an internal part of the library.&lt;/p&gt;

&lt;p&gt;If you wonder how those changes apply to the Pascal Triangle test, I am happy to say that time dropped from 10 to 4.3 seconds. It's now less than half of the previous result! The test takes place in a throttled environment (CPU and network are slowed down), so the differences between scores are more important than absolute time, so check out other results on the project &lt;a href="https://vogloblinsky.github.io/web-components-benchmark/" rel="noopener noreferrer"&gt;home page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The hybrids library is not yet the number one in the Pascal Triangle test. However, take into account that this is a synthetic test. I would not recommend creating UI, which at one time renders more than five thousands of elements. What is worth to mention is how hybrids performs when we increase the number of rows. When we change the length property from one hundred to one hundred and one, re-render takes  100ms in the throttled environment, while without throttling, it's less than 35ms!&lt;/p&gt;

&lt;p&gt;On another hand, Todo List test is much closer to real usage. Before the changes hybrids was somewhere in the middle, but now results are much better - in some areas it is even close to the best in the competition!&lt;/p&gt;

&lt;h3&gt;
  
  
  Unleashed the power of cache
&lt;/h3&gt;

&lt;p&gt;Decoupling change detection from the DOM has one unique hidden goal, which is not directly related to performance issues. From now, it is possible to attach a cache mechanism to objects, that are not HTML elements. Why is it important? A few months ago, I started working on a new built-in factory - the store. The main goal is to create state management for asynchronous data using all of the hybrids goodies. Without the ability to apply the cache mechanism on that data, it would not be possible. As usual in hybrids, this factory won't be another clone of an existing solution. The idea is to combine fetching, storing, caching, and serving data to your elements in a seamless way as possible. Stay tuned for more details in the next months!&lt;/p&gt;

&lt;h3&gt;
  
  
  What's next?
&lt;/h3&gt;

&lt;p&gt;The DOM rendering will be as fast as its the weakest point. The render factory is, for now, free of performance issues, but what about the template engine? In the next post of the series, we will learn more about the features of the built-in template engine. Even though it may look similar to lit-html at first, with a closer look, it shows unique patterns taken from core concepts of the library.&lt;/p&gt;

&lt;p&gt;In the meantime, you can read more about the library at the &lt;a href="https://hybrids.js.org" rel="noopener noreferrer"&gt;project documentation&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;🙏 &lt;strong&gt;How can you support the project?&lt;/strong&gt; Give the GitHub repository a ⭐️, comment below ⬇️ and spread the news about hybrids to the world 📢!&lt;/p&gt;




&lt;p&gt;&lt;small&gt;Cover photo by &lt;a href="https://unsplash.com/photos/E4kKGI4oGaU" rel="noopener noreferrer"&gt;Saffu&lt;/a&gt; on &lt;a href="https://unsplash.com" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>webcomponents</category>
      <category>functional</category>
    </item>
    <item>
      <title>Say goodbye to lifecycle methods, and focus on productive code</title>
      <dc:creator>Dominik Lubański</dc:creator>
      <pubDate>Tue, 29 Jan 2019 09:28:42 +0000</pubDate>
      <link>https://dev.to/hybrids/how-to-say-goodbye-to-lifecycle-methods-and-focus-on-productive-code-175</link>
      <guid>https://dev.to/hybrids/how-to-say-goodbye-to-lifecycle-methods-and-focus-on-productive-code-175</guid>
      <description>&lt;p&gt;&lt;em&gt;This is the second in a series of posts about core concepts of &lt;a href="https://github.com/hybridsjs/hybrids" rel="noopener noreferrer"&gt;hybrids&lt;/a&gt; - a library for creating Web Components with simple and functional API.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One of the most rooted features of component-based UI libraries is a complex lifecycle. It is a group of methods, which provide full control over the state of the component that may change over time. Usually, libraries use self-explaining name convention and call did* methods after something happens and will* before the change. While studying the library docs, we often find a whole range of possibilities, which can lead to confusion or even frustration. After all, you need to have an in-depth understanding to create correct and efficient code. For example, the component state may depend on a specific sequence of events in time, which makes the code hard to test and eventually maintain or extend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it so bad?
&lt;/h2&gt;

&lt;p&gt;Let's face it two obscure facts about lifecycle methods. Firstly, they shift the burden of state management from the library to us. As it might look legit, it usually means, that we have to write more redundant code manually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;componentDidUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;prevProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// do something...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the above example, the library provides a map of previous properties, but it doesn't inform which of them has a new value. We have to create conditions explicitly to be sure that our code is called only if the &lt;code&gt;name&lt;/code&gt; property has changed.&lt;/p&gt;

&lt;p&gt;In another hand, if a component requires asynchronous data, lifecycle structure may force to fetch data twice - for the first time in something like &lt;code&gt;componentDidMount()&lt;/code&gt; method, and then each time in &lt;code&gt;componentDidUpdate()&lt;/code&gt; when the dependencies change:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getUser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;componentDidMount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;componentDidUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;prevProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Even though we have extracted redundant logic into the &lt;code&gt;fetch()&lt;/code&gt; method, it has to be called twice in two separate lifecycle methods. &lt;/p&gt;

&lt;p&gt;Both code examples might look familiar to you. In fact, they represent what the &lt;code&gt;React.Component&lt;/code&gt; class provides. React of course is not a web components library, but &lt;a href="https://lit-element.polymer-project.org/guide/lifecycle" rel="noopener noreferrer"&gt;LitElement&lt;/a&gt;, &lt;a href="https://github.com/Tencent/omi#lifecycle" rel="noopener noreferrer"&gt;Omi&lt;/a&gt;, &lt;a href="http://slimjs.com/#/component-lifecycle" rel="noopener noreferrer"&gt;Slim.js&lt;/a&gt;, &lt;a href="https://stenciljs.com/docs/component-lifecycle" rel="noopener noreferrer"&gt;Stencil&lt;/a&gt; and many others follow the trends, and they implemented very similar concepts (use the links to go to the lifecycle section of libraries documentation).&lt;/p&gt;

&lt;p&gt;In the first post of the series, we have learned how we can switch component definition from the class syntax into the map of independent property descriptors. If you haven't read it yet, it's a good moment to do so:&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/hybrids" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1991%2F4075a9b6-6447-4659-a635-43318ef9f5b3.png" alt="hybrids"&gt;
      &lt;div class="ltag__link__user__pic"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F106561%2Ffb8a7967-58fa-45f9-9abe-45a4c14858a8.png" alt=""&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/hybrids/from-classes-to-plain-objects-and-pure-functions-2gip" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;From classes to plain objects and pure functions&lt;/h2&gt;
      &lt;h3&gt;Dominik Lubański for hybrids ・ Jan 10 '19&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webcomponents&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#functional&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;p&gt;This time we will go deeper into the property descriptor definition and learn more about cache mechanism, change detection and its &lt;code&gt;connect&lt;/code&gt; method.&lt;/p&gt;

&lt;h2&gt;
  
  
  Different approach
&lt;/h2&gt;

&lt;p&gt;Lifecycle methods pushed us to think more about &lt;em&gt;when&lt;/em&gt; something happens rather than to define &lt;em&gt;how&lt;/em&gt; we can get &lt;em&gt;what&lt;/em&gt; we need. What would you say if you could focus on value computations and leave the rest to the library? &lt;/p&gt;

&lt;p&gt;The hybrids property descriptors concept introduced much more than only a middleware for holding property value. The library provides a complete cache and change detection mechanism.&lt;/p&gt;

&lt;p&gt;A component, which requires data fetched asynchronously can be defined with hybrids just like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hybrids&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getUser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AsyncUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
    &amp;lt;div&amp;gt;
      &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
          &amp;lt;span&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/span&amp;gt;
        `&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;
    &amp;lt;/div&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://stackblitz.com/edit/hybrids-async-user?file=async-user.js" rel="noopener noreferrer"&gt;Click here to play with a live example on ⚡️StackBlitz&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above definition includes &lt;code&gt;userId&lt;/code&gt;, &lt;code&gt;data&lt;/code&gt; and &lt;code&gt;render&lt;/code&gt; descriptors. The &lt;code&gt;data&lt;/code&gt; property depends on &lt;code&gt;userId&lt;/code&gt; and returns a promise with user details. Don't bother much about the &lt;code&gt;render&lt;/code&gt; property for now. You should need to know now that it uses under the hood the &lt;code&gt;render&lt;/code&gt; factory (using property translation), which uses &lt;code&gt;html&lt;/code&gt; function to create and update contents of the custom element. In the body of the template, we are using dynamic value, which resolves &lt;code&gt;data&lt;/code&gt; promise to an element with the first name of the user.&lt;/p&gt;
&lt;h2&gt;
  
  
  Cache mechanism
&lt;/h2&gt;

&lt;p&gt;The cache mechanism is attached to the getter and setter of every property defined by the library. For &lt;code&gt;set&lt;/code&gt; method it automatically updates the cache if calculation returns a new value. For &lt;code&gt;get&lt;/code&gt; method cache ensures that the value is only computed if needed, for example, when one of the property dependency has changed. In our example, it means, that &lt;code&gt;getUser()&lt;/code&gt; will be called to set an initial value and only when &lt;code&gt;userId&lt;/code&gt; will change. How does it work?&lt;/p&gt;

&lt;p&gt;The cache controls the &lt;code&gt;data&lt;/code&gt;, as well as &lt;code&gt;userId&lt;/code&gt; property. When &lt;code&gt;userId&lt;/code&gt; is called inside of the &lt;code&gt;data&lt;/code&gt; getter, the cache can save it as a &lt;code&gt;data&lt;/code&gt; dependency. Next time, when we call &lt;code&gt;data&lt;/code&gt;, cache checks &lt;code&gt;userId&lt;/code&gt; from the cache and calls &lt;code&gt;getUser(userId)&lt;/code&gt; only if &lt;code&gt;userId&lt;/code&gt; has changed. Otherwise, it returns the last cached value and omits getter. The cache is global for all elements defined by the library so we can depend on properties defined in other elements too!&lt;/p&gt;

&lt;p&gt;The cache concept uses the fact that properties are never computed if they are not called (even if the dependencies have changed). You could try to get a value of &lt;code&gt;data&lt;/code&gt; manually, and you would see, that it returns the same promise all the time. However, if you change &lt;code&gt;userId&lt;/code&gt; property, &lt;code&gt;data&lt;/code&gt; will return a new promise called next time.&lt;/p&gt;
&lt;h2&gt;
  
  
  Simplified lifecycle
&lt;/h2&gt;

&lt;p&gt;In the first post, we have learned that the property descriptor may have &lt;code&gt;get&lt;/code&gt; and &lt;code&gt;set&lt;/code&gt; methods. Actually, you can define two more for property lifecycle control - &lt;code&gt;connect&lt;/code&gt; and &lt;code&gt;observe&lt;/code&gt; method. &lt;code&gt;connect&lt;/code&gt; method can return a function, which is called when an element is disconnected. While the &lt;code&gt;observe&lt;/code&gt; method is called asynchronously when the property value changes.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{...},&lt;/span&gt;
  &lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{...},&lt;/span&gt;
  &lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;invalidate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{...};&lt;/span&gt; &lt;span class="c1"&gt;// disconnect&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{...},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;However, in the above &lt;code&gt;AsyncUser&lt;/code&gt; example we didn't have to use it explicitly. We even didn't have to create property descriptors at all! If we would take all the concepts together, we may start to see a bigger picture here. The raw descriptor provides all the required features to create stateful properties. Then the library adds on top of that cache mechanism. However, the preferred way to define properties is to use built-in or custom factories (functions, that produce descriptors). As the property definition is independent, you can re-use factories wherever you want. As the result, you don't have to define &lt;code&gt;connect&lt;/code&gt; method by yourself, and you can focus on productive coding in a declarative way!&lt;/p&gt;
&lt;h2&gt;
  
  
  Invalidation
&lt;/h2&gt;

&lt;p&gt;You may have noticed a third argument of the &lt;code&gt;connect&lt;/code&gt; method - &lt;code&gt;invalidate&lt;/code&gt; callback. If a property has only a getter, but it depends on third-party tools, &lt;code&gt;invalidate&lt;/code&gt; is a clever way to notify cache, that value should be computed next time. Because of the functional structure, it is super easy to create properties connected to external state managers like redux:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./store&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mapState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;mapState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;invalidate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;invalidate&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Redux &lt;code&gt;subscribe&lt;/code&gt; method takes a callback where we can pass &lt;code&gt;invalidate&lt;/code&gt;. It returns unsubscribe function so we can call it in the connect method defined as an arrow function. We can use the factory in the component definition, like in the following example:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./store&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;connect&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./connectFactory&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;userDetails&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Change detection mechanism
&lt;/h2&gt;

&lt;p&gt;In the last part of the post let's go back to &lt;code&gt;render&lt;/code&gt; property. If the library does not call getters for us, how is it possible that our component works? Even though &lt;code&gt;render&lt;/code&gt; might look special, is it the same property descriptor as the rest. The difference is in how the &lt;code&gt;render&lt;/code&gt; factory uses &lt;code&gt;connect&lt;/code&gt; and &lt;code&gt;observe&lt;/code&gt; methods.&lt;/p&gt;

&lt;p&gt;The best way to understand how &lt;code&gt;render&lt;/code&gt; works is to built a simplified version:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attachShadow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Our &lt;code&gt;render&lt;/code&gt; factory returns descriptor with &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;connect&lt;/code&gt; and &lt;code&gt;observe&lt;/code&gt; methods. We took advantage of the cache mechanism, so our getter calls &lt;code&gt;fn&lt;/code&gt; and saves its dependencies. The property value will be only recalculated if one of the properties used in the &lt;code&gt;fn&lt;/code&gt; changes.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;connect&lt;/code&gt; creates &lt;code&gt;shadowRoot&lt;/code&gt; if it is not already there. Then we want to call &lt;code&gt;fn&lt;/code&gt; whenever dependencies change. It is exactly what &lt;code&gt;observe&lt;/code&gt; method provides. It might looks familiar to &lt;code&gt;componentDidUpdate()&lt;/code&gt; callbacks from other libraries. Eventually, we want to do something when the change occurs. However, the idea behind the &lt;code&gt;observe&lt;/code&gt; method is much deeper. The library calls it only when the value of the property has changed. This method is also called only once during the current event loop, because of the internal queue scheduled with &lt;code&gt;requestAnimationFrame&lt;/code&gt; API. We don't have to bother to check what property has a new value or not because we covered it with the cache mechanism. &lt;/p&gt;
&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;It might be a lot of new stuff to process. For sure, hybrids didn't give up on lifecycle methods. They are just redesigned and implemented in the opposite direction to patterns known from other libraries. In the explained component example, the chain of cause and effect goes from render property to data (in other libraries it would go from fetching data to rendering new state). A function, which creates a template, wants user details, and only because of that they are fetched, and they eventually trigger an update of the template. If in some condition the template would not require those data, they would not be fetched at all.&lt;/p&gt;

&lt;p&gt;We can call it &lt;strong&gt;simplified lifecycle&lt;/strong&gt;. If we add on top of that smart cache mechanism and all already known property-based concepts, it changes everything. We can shift the most of state-related responsibility to the library and focus on the business logic of our components. Usually, the component requires a list of properties for holding simple or computed values and render method for creating element structure. If we need something not covered by the library, we can easily create reusable factories and still do not use lifecycle methods directly.&lt;/p&gt;
&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;Today, we have scratched the surface of the &lt;code&gt;render&lt;/code&gt; factory. In the next post of the series, we will learn more about render factory provided by the library, as well as the rich template engine built on top of tagged template literals.&lt;/p&gt;

&lt;p&gt;In the meantime, you can read more about the hybrids library at the &lt;a href="https://hybrids.js.org" rel="noopener noreferrer"&gt;project documentation&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/hybridsjs" rel="noopener noreferrer"&gt;
        hybridsjs
      &lt;/a&gt; / &lt;a href="https://github.com/hybridsjs/hybrids" rel="noopener noreferrer"&gt;
        hybrids
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Extraordinary JavaScript UI framework with unique declarative and functional architecture
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://raw.githubusercontent.com/hybridsjs/hybrids/main/docs/assets/hybrids-full-logo.svg?sanitize=true"&gt;&lt;img alt="hybrids" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fhybridsjs%2Fhybrids%2Fmain%2Fdocs%2Fassets%2Fhybrids-full-logo.svg%3Fsanitize%3Dtrue"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/hybridsjs/hybrids/actions/workflows/test.yml?query=branch%3Amain" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/hybridsjs/hybrids/actions/workflows/test.yml/badge.svg" alt="build status"&gt;&lt;/a&gt;
&lt;a href="https://coveralls.io/github/hybridsjs/hybrids?branch=main" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/40834886f5f3644acc7d6f05320877acfbb6cd417cff0c0ffb5fd2a839a92f95/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f687962726964736a732f687962726964732f62616467652e7376673f6272616e63683d6d61696e" alt="coverage status"&gt;&lt;/a&gt;
&lt;a href="https://www.npmjs.com/package/hybrids" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4123b7442ee41f60f5c085274b028fdb18d38fe0ef50fc992bd97be007372760/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f687962726964732e7376673f7374796c653d666c6174" alt="npm version"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An extraordinary JavaScript framework for creating client-side web applications, UI components libraries, or single web components with unique mixed declarative and functional architecture&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Hybrids&lt;/strong&gt; provides a complete set of features for building modern web applications:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Component Model&lt;/strong&gt; based on plain objects and pure functions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global State Management&lt;/strong&gt; with external storages, offline caching, relations, and more&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;App-like Routing&lt;/strong&gt; based on the graph structure of views&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layout Engine&lt;/strong&gt; making UI layouts development much faster&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Localization&lt;/strong&gt; with automatic translation of the templates content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hot Module Replacement&lt;/strong&gt; support without any additional configuration&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Documentation&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;The project documentation is available at the &lt;a href="https://hybrids.js.org" rel="nofollow noopener noreferrer"&gt;hybrids.js.org&lt;/a&gt; site.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quick Look&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Component Model&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;It's based on plain objects and pure functions&lt;sup&gt;&lt;a href="https://github.com/hybridsjs/hybrids#user-content-fn-1-46d4d5c5366fe6106a0b64bf37c6578b" id="user-content-fnref-1-46d4d5c5366fe6106a0b64bf37c6578b" rel="noopener noreferrer"&gt;1&lt;/a&gt;&lt;/sup&gt;, still using the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components" rel="nofollow noopener noreferrer"&gt;Web Components API&lt;/a&gt; under the hood:&lt;/p&gt;
&lt;div class="highlight highlight-source-js notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-s1"&gt;html&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;define&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s"&gt;"hybrids"&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-k"&gt;function&lt;/span&gt; &lt;span class="pl-en"&gt;increaseCount&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;host&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-s1"&gt;host&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;count&lt;/span&gt; &lt;span class="pl-c1"&gt;+=&lt;/span&gt; &lt;span class="pl-c1"&gt;1&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;

&lt;span class="pl-k"&gt;export&lt;/span&gt; &lt;span class="pl-k"&gt;default&lt;/span&gt; &lt;span class="pl-en"&gt;define&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-c1"&gt;tag&lt;/span&gt;: &lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/hybridsjs/hybrids" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





&lt;p&gt;🙏 &lt;strong&gt;How can you support the project?&lt;/strong&gt; Give the GitHub repository a ⭐️, comment below ⬇️ and spread the news about hybrids to the world 📢!&lt;/p&gt;




&lt;p&gt;👋 &lt;strong&gt;Welcome dev.to community!&lt;/strong&gt; My name is Dominik, and this is my third blog post ever written - any kind of feedback is welcome ❤️.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Cover photo by &lt;a href="https://unsplash.com/photos/7KLa-xLbSXA" rel="noopener noreferrer"&gt;Paul Skorupskas&lt;/a&gt; on &lt;a href="https://unsplash.com" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>webcomponents</category>
      <category>functional</category>
    </item>
    <item>
      <title>From classes to plain objects and pure functions</title>
      <dc:creator>Dominik Lubański</dc:creator>
      <pubDate>Thu, 10 Jan 2019 19:00:37 +0000</pubDate>
      <link>https://dev.to/hybrids/from-classes-to-plain-objects-and-pure-functions-2gip</link>
      <guid>https://dev.to/hybrids/from-classes-to-plain-objects-and-pure-functions-2gip</guid>
      <description>&lt;p&gt;&lt;em&gt;This is the first in a series of posts about core concepts of &lt;a href="https://github.com/hybridsjs/hybrids" rel="noopener noreferrer"&gt;hybrids&lt;/a&gt; - a library for creating Web Components with simple and functional API.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;ES2015 has introduced classes that are now widely used in UI libraries and frameworks. However, are they the best way for creating component-based logic in JavaScript? In my last post, I've highlighted some of the main classes pitfalls:&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/smalluban" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F106561%2Ffb8a7967-58fa-45f9-9abe-45a4c14858a8.png" alt="smalluban"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/smalluban/do-we-really-need-classes-in-javascript-after-all-91n" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Do we really need classes in JavaScript after all?&lt;/h2&gt;
      &lt;h3&gt;Dominik Lubański ・ Dec 11 '18&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#discuss&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webcomponents&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;The hybrids library is the result of research on how we can take a different approach, and create simple and functional tools for building web components. However, the only way to create a custom element is to use a &lt;code&gt;class&lt;/code&gt;, which extends &lt;code&gt;HTMLElement&lt;/code&gt;, and define it with Custom Elements API. There is just no other way (you can also use function constructor with properly reflected &lt;code&gt;super()&lt;/code&gt; call). So, how is it possible that hybrids uses plain objects instead of classes?&lt;/p&gt;

&lt;p&gt;The answer is a combination of three property-related concepts used together: property descriptors, property factories, and property translation. Let's break down those concepts into the step by step process with a simple custom element definition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Use Custom Elements API
&lt;/h2&gt;

&lt;p&gt;For a better understanding of the process, we are going to use an example with minimal requirements of the Custom Elements API. The goal here is to show how we can switch from class definition to plain object with pure functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dominik&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lubański&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Our custom element definition has two simple properties (&lt;code&gt;firstName&lt;/code&gt; and &lt;code&gt;lastName&lt;/code&gt;) and one computed property, which returns the concatenation of the first two. The example does not contain methods, but they can be easily transformed using the same process (you can define a method as computed property, which returns a function).&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2: Desugar class syntax using the prototype
&lt;/h2&gt;

&lt;p&gt;The class syntax is nothing more than syntactical sugar on top of the function and its prototype. Every class definition has &lt;code&gt;prototype&lt;/code&gt; property, which holds the class methods (expect &lt;code&gt;constructor&lt;/code&gt;). What is important, we can change it after the definition, so the body of the class can be empty. Properties can be defined directly on the &lt;code&gt;MyElement.prototype&lt;/code&gt; using &lt;code&gt;Object.defineProperty()&lt;/code&gt; method. The prototype delegation may work unexpected with normal values, so we should define only computed properties, which return values related to the context.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;// before: this.firstName in constructor()&lt;/span&gt;
&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firstName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_firstName&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dominik&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_firstName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;configurable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// before: this.lastName in constructor()&lt;/span&gt;
&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lastName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_lastName&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lubański&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_lastName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;configurable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// before: fullName computed property in the class body&lt;/span&gt;
&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fullName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;configurable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It may seem that we have taken a step back. The code has become more verbose and redundant (A simple structure of the class definition was one of the reasons for the introduction of the class syntax). Also, the current implementation is not consistent with the original one. If we set one of the properties to falsy value, it will still return a default value. We'll take care of that in the fifth step. For now, we have to focus on cleaning out our definition.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3: Hide redundant code into the custom definition
&lt;/h2&gt;

&lt;p&gt;All properties are defined by the &lt;code&gt;Object.defineProperty()&lt;/code&gt; method. We can extract passed arguments to a map of property names and descriptors, and put the rest into the custom function, which will replace &lt;code&gt;customElements.define()&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dominik&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_firstName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_firstName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ConFrontJS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_lastName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_lastName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;defineElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is how the &lt;strong&gt;property descriptors&lt;/strong&gt; concept works. The &lt;code&gt;MyElement&lt;/code&gt; is now a plain object with a map of property descriptors, which we define on the custom element prototype.&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;defineElement()&lt;/code&gt; function could be defined like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;defineElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tagName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;descriptors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Wrapper&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;descriptors&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;descriptors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;configurable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tagName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Wrapper&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 4: Get rid of "this"
&lt;/h2&gt;

&lt;p&gt;The custom function opens the way for further optimization. From now, we have all control over the structure of the input. Instead of passing through property descriptors to &lt;code&gt;Object.defineProperty()&lt;/code&gt;, a function can create them dynamically. We can finally kill the last standing bastion - &lt;code&gt;this&lt;/code&gt; keyword.&lt;/p&gt;

&lt;p&gt;The first argument of &lt;code&gt;get&lt;/code&gt; and &lt;code&gt;set&lt;/code&gt; methods may become a &lt;code&gt;host&lt;/code&gt; - an element instance. Because of that, we no longer have to access a custom element instance by &lt;code&gt;this&lt;/code&gt; keyword. Moreover, methods are &lt;a href="https://en.wikipedia.org/wiki/Pure_function" rel="noopener noreferrer"&gt;pure&lt;/a&gt; - they depend only on arguments and have no side effects. Removing context also allows using some of the useful features of ES2015 like arrow functions and destructuring function parameters.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;_firstName&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_firstName&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dominik&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_firstName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;_lastName&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_lastName&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lubański&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_lastName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Our definition has shrunk significantly. We have replaced ordinary functions with arrow functions, and the &lt;code&gt;host&lt;/code&gt; parameter has been destructured for the &lt;code&gt;get&lt;/code&gt; calls.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 5: Add middleware to save property value
&lt;/h2&gt;

&lt;p&gt;A computed property by design doesn't hold its value. The definition is a pair of functions (not values), which one of them returns the current state of the property taken from external dependencies, and second updates those external dependencies. In our current solution &lt;code&gt;firstName&lt;/code&gt; and &lt;code&gt;lastName&lt;/code&gt; properties depend on &lt;code&gt;_firstName&lt;/code&gt; and &lt;code&gt;_lastName&lt;/code&gt; properties from the custom element instance (they are defined when &lt;code&gt;set&lt;/code&gt; method is invoked for the first time).&lt;/p&gt;

&lt;p&gt;Using the fact from the third step, we can introduce a local variable during the property definition in our custom define function. The value can be passed to &lt;code&gt;get&lt;/code&gt; and &lt;code&gt;set&lt;/code&gt; methods as a new last argument - &lt;code&gt;lastValue&lt;/code&gt;. From now, &lt;code&gt;get&lt;/code&gt; and &lt;code&gt;set&lt;/code&gt; methods should return the current value of the property.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dominik&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lubański&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can notice how default values are handled now. We've started using another ES2015 feature - default parameters. Those arguments are initialized with default values if no value or &lt;code&gt;undefined&lt;/code&gt; is passed. It's much better than the solution with &lt;code&gt;||&lt;/code&gt; operator. Although, the &lt;code&gt;firstName&lt;/code&gt; and &lt;code&gt;lastName&lt;/code&gt; sill return &lt;code&gt;Dominik&lt;/code&gt; or &lt;code&gt;Lubański&lt;/code&gt; if we set them to &lt;code&gt;undefined&lt;/code&gt; (In a real-world scenario, it is not a problem, as we can use a built-in factory from the library, which covers that case).&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 6: Introduce property factory
&lt;/h2&gt;

&lt;p&gt;After all of the optimizations, we can find redundant code again - &lt;code&gt;firstName&lt;/code&gt; and &lt;code&gt;lastName&lt;/code&gt; property descriptors have become almost the same. Only a default value is different. To make it cleaner and simpler we can create a function - property factory, which returns property descriptor parameterized by the arguments.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;defaulValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We can now replace &lt;code&gt;firstName&lt;/code&gt; and &lt;code&gt;lastName&lt;/code&gt; descriptors with &lt;code&gt;property()&lt;/code&gt; function invocation:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./propertyFactory&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dominik&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lubański&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;With the &lt;strong&gt;property factories&lt;/strong&gt; concept, we can define properties with only one line of code! Factories hide implementation details and minimize redundant code.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 7: Introduce property translation
&lt;/h2&gt;

&lt;p&gt;We still have the last concept to follow. Our custom define function takes only descriptors, which are objects with pre-defined structure. What could happen if we allowed passing primitives, functions, or even objects, but without defined methods?&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;property translation&lt;/strong&gt; concept provides a set of rules for translating property definition that does not match property descriptor structure. It supports primitives, functions, or even objects (without descriptors keys). &lt;/p&gt;

&lt;p&gt;For example, if we set the value of the &lt;code&gt;firstName&lt;/code&gt; property to a primitive, the library uses the built-in &lt;code&gt;property&lt;/code&gt; factory to define it on the prototype of the custom element. In another case, if you set property value as a function, it is translated to a descriptor object with &lt;code&gt;get&lt;/code&gt; method. &lt;/p&gt;

&lt;p&gt;In the result, custom element definition can be a simple structure of default values and pure functions without external dependencies:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dominik&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lubański&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Here is the end of today's coding journey. In the last step we have created the simplest possible definition without &lt;code&gt;class&lt;/code&gt; and &lt;code&gt;this&lt;/code&gt; syntax, but with truly composable structure with pure functions. &lt;/p&gt;

&lt;p&gt;The whole process has shown that it is possible to replace imperative and stateful class definition with a simple concept of property descriptors. The other two, property factories and property translation, allow simplifying the definition either further.&lt;/p&gt;
&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;Usually, custom elements do much more than our simple example. They perform async calls, observe and react to changes in the internal and external state and many more. To cover those features, component-based libraries introduced sophisticated lifecycle methods and mechanisms for managing external and internal state. What would you say if all of that was no longer needed?&lt;/p&gt;

&lt;p&gt;In the next post of the series, we will go deeper into the property descriptor definition and know more about the cache mechanism, change detection and independent &lt;code&gt;connect&lt;/code&gt; method.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/hybrids" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1991%2F4075a9b6-6447-4659-a635-43318ef9f5b3.png" alt="hybrids"&gt;
      &lt;div class="ltag__link__user__pic"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F106561%2Ffb8a7967-58fa-45f9-9abe-45a4c14858a8.png" alt=""&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/hybrids/how-to-say-goodbye-to-lifecycle-methods-and-focus-on-productive-code-175" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Say goodbye to lifecycle methods, and focus on productive code&lt;/h2&gt;
      &lt;h3&gt;Dominik Lubański for hybrids ・ Jan 29 '19&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webcomponents&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#functional&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;p&gt;You can read more about the hybrids library at the &lt;a href="https://hybrids.js.org" rel="noopener noreferrer"&gt;project documentation&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/hybridsjs" rel="noopener noreferrer"&gt;
        hybridsjs
      &lt;/a&gt; / &lt;a href="https://github.com/hybridsjs/hybrids" rel="noopener noreferrer"&gt;
        hybrids
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Extraordinary JavaScript UI framework with unique declarative and functional architecture
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://raw.githubusercontent.com/hybridsjs/hybrids/main/docs/assets/hybrids-full-logo.svg?sanitize=true"&gt;&lt;img alt="hybrids" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fhybridsjs%2Fhybrids%2Fmain%2Fdocs%2Fassets%2Fhybrids-full-logo.svg%3Fsanitize%3Dtrue"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/hybridsjs/hybrids/actions/workflows/test.yml?query=branch%3Amain" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/hybridsjs/hybrids/actions/workflows/test.yml/badge.svg" alt="build status"&gt;&lt;/a&gt;
&lt;a href="https://coveralls.io/github/hybridsjs/hybrids?branch=main" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/40834886f5f3644acc7d6f05320877acfbb6cd417cff0c0ffb5fd2a839a92f95/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f687962726964736a732f687962726964732f62616467652e7376673f6272616e63683d6d61696e" alt="coverage status"&gt;&lt;/a&gt;
&lt;a href="https://www.npmjs.com/package/hybrids" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4123b7442ee41f60f5c085274b028fdb18d38fe0ef50fc992bd97be007372760/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f687962726964732e7376673f7374796c653d666c6174" alt="npm version"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An extraordinary JavaScript framework for creating client-side web applications, UI components libraries, or single web components with unique mixed declarative and functional architecture&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Hybrids&lt;/strong&gt; provides a complete set of features for building modern web applications:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Component Model&lt;/strong&gt; based on plain objects and pure functions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global State Management&lt;/strong&gt; with external storages, offline caching, relations, and more&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;App-like Routing&lt;/strong&gt; based on the graph structure of views&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layout Engine&lt;/strong&gt; making UI layouts development much faster&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Localization&lt;/strong&gt; with automatic translation of the templates content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hot Module Replacement&lt;/strong&gt; support without any additional configuration&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Documentation&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;The project documentation is available at the &lt;a href="https://hybrids.js.org" rel="nofollow noopener noreferrer"&gt;hybrids.js.org&lt;/a&gt; site.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quick Look&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Component Model&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;It's based on plain objects and pure functions&lt;sup&gt;&lt;a href="https://github.com/hybridsjs/hybrids#user-content-fn-1-35aa49a907f12a61bdaa6006d9223647" id="user-content-fnref-1-35aa49a907f12a61bdaa6006d9223647" rel="noopener noreferrer"&gt;1&lt;/a&gt;&lt;/sup&gt;, still using the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components" rel="nofollow noopener noreferrer"&gt;Web Components API&lt;/a&gt; under the hood:&lt;/p&gt;
&lt;div class="highlight highlight-source-js notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-s1"&gt;html&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;define&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s"&gt;"hybrids"&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-k"&gt;function&lt;/span&gt; &lt;span class="pl-en"&gt;increaseCount&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;host&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-s1"&gt;host&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;count&lt;/span&gt; &lt;span class="pl-c1"&gt;+=&lt;/span&gt; &lt;span class="pl-c1"&gt;1&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;

&lt;span class="pl-k"&gt;export&lt;/span&gt; &lt;span class="pl-k"&gt;default&lt;/span&gt; &lt;span class="pl-en"&gt;define&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-c1"&gt;tag&lt;/span&gt;: &lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/hybridsjs/hybrids" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





&lt;p&gt;🙏 &lt;strong&gt;How can you support the project?&lt;/strong&gt; Give the GitHub repository a ⭐️, comment below ⬇️ and spread the news about hybrids to the world 📢!&lt;/p&gt;




&lt;p&gt;👋 &lt;strong&gt;Welcome dev.to community!&lt;/strong&gt; My name is Dominik, and this is my second blog post ever written - any kind of feedback is welcome ❤️.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Cover photo by &lt;a href="https://unsplash.com/photos/sWGDbVPcPdg" rel="noopener noreferrer"&gt;Patrick Robert Doyle&lt;/a&gt; on &lt;a href="https://unsplash.com" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>webcomponents</category>
      <category>javascript</category>
      <category>functional</category>
    </item>
  </channel>
</rss>
