<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Late Night Coder]]></title><description><![CDATA[I’m a software ninja 🥷  who loves abstractions and spread functional programming everywhere.]]></description><link>https://aniketjha.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 22 Apr 2026 20:34:29 GMT</lastBuildDate><atom:link href="https://aniketjha.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Creating Tiptap Emoji Picker]]></title><description><![CDATA[When you are building a text editor for general-purpose writing, sooner or later you will need to support emoji’s for your users.
In this blog post, we will learn to create an emoji picker for your tiptap-based editor.

Let’s define the EmojiData Mod...]]></description><link>https://aniketjha.dev/creating-tiptap-emoji-picker</link><guid isPermaLink="true">https://aniketjha.dev/creating-tiptap-emoji-picker</guid><category><![CDATA[prosemirror]]></category><category><![CDATA[emoji picker]]></category><category><![CDATA[tiptap]]></category><category><![CDATA[emoji]]></category><dc:creator><![CDATA[Aniket Jha]]></dc:creator><pubDate>Sun, 15 Sep 2024 13:49:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1726406963089/d12c7d6e-f8f0-47c2-9a9d-56d36560e7c3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When you are building a text editor for general-purpose writing, sooner or later you will need to support emoji’s for your users.</p>
<p>In this blog post, we will learn to create an <a target="_blank" href="https://github.com/vtechguys/tiptap-emoji-picker/tree/main">emoji picker for your tiptap-based editor</a>.</p>
<p><img src="https://private-user-images.githubusercontent.com/29702340/361143849-baed9352-b6a3-481b-8474-b0cdc36856d5.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjY0MDgyMzIsIm5iZiI6MTcyNjQwNzkzMiwicGF0aCI6Ii8yOTcwMjM0MC8zNjExNDM4NDktYmFlZDkzNTItYjZhMy00ODFiLTg0NzQtYjBjZGMzNjg1NmQ1LmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA5MTUlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwOTE1VDEzNDUzMlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTJjYWZhM2YxNWY3MDhkZmJjMmRmNzQ0MTA5MjE3ZWI2YWVlYTM4YzUxZjYyMTNmMTMwYTBkNThmYWQ1NTk2ZWYmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.H474N18J5r1CsyRhlwBfvfCpDzyDplrmK2IBBT2FLz0" alt="file" /></p>
<p>Let’s define the <code>EmojiData</code> Model first.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> EmojiData {
 <span class="hljs-comment">/**
   Label, name, meaning, descritption of emoji, user search can happen
   on this text.
 **/</span>
 annotation: <span class="hljs-built_in">string</span>;

<span class="hljs-comment">/**
 power users uses emoji codes example `:cool:` will insert  emoji
**/</span>
shortcodes: <span class="hljs-built_in">string</span>[];

<span class="hljs-comment">/**
Unicode or actual emoji character: 😁/🥵/💙
**/</span>
emoji: <span class="hljs-built_in">string</span>; 

<span class="hljs-comment">/**
fallback url to be used in case where current env doesn't support
this emoji character, or it can be used for custom emojis
**/</span>
url?: <span class="hljs-built_in">string</span>;
}
</code></pre>
<p>Our Emoji will be a custom node and not a simple character as the env platform may not support that emoji or we want to use custom emojis like slack.</p>
<p>Let’s get our requirement clear for emoji node:</p>
<ul>
<li><p>It should insert actual emoji character (text: inline, atom)</p>
</li>
<li><p>Emoji should be copied as unicode to clipboard (selectable)</p>
</li>
<li><p>If unsupported we should render the provided fallback emoji.</p>
</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-comment">// Emoji-Node.ts</span>

<span class="hljs-keyword">import</span> { Node } <span class="hljs-keyword">from</span> <span class="hljs-string">"@tiptap/core"</span>;
<span class="hljs-keyword">import</span> isEmojiSupported <span class="hljs-keyword">from</span> <span class="hljs-string">"is-emoji-supported"</span>;




<span class="hljs-comment">/**
emoji node:
&lt;span data-node="emoji" data-emoji="🥵" data-emoji-url="..."&gt;
 &lt;span &gt;🥵&lt;/span&gt;
 &lt;img src="..." /&gt;
&lt;/span&gt;
**/</span>

<span class="hljs-keyword">const</span> EmojiNode = Node.create({
 <span class="hljs-comment">// name of our node with which this will be registered</span>
 <span class="hljs-comment">// Node.name</span>
 name: <span class="hljs-string">'emoji'</span>,
 <span class="hljs-comment">// we want it to be inline element</span>
 group: <span class="hljs-string">"inline"</span>,
 inline: <span class="hljs-literal">true</span>,
 <span class="hljs-comment">// we want node to be selectable</span>
 selectable: <span class="hljs-literal">true</span>,
 <span class="hljs-comment">// we want it as non editable node</span>
 <span class="hljs-comment">// https://tiptap.dev/docs/editor/core-concepts/schema#atom</span>
 atom: <span class="hljs-literal">true</span>,

 <span class="hljs-comment">// add attributes to the custom node, these appear on the model/schema</span>
 addAttributes() {
    <span class="hljs-keyword">return</span> {
     <span class="hljs-comment">// EmojiData['emoji']</span>
      emoji: { <span class="hljs-keyword">default</span>: <span class="hljs-literal">null</span> },
      <span class="hljs-comment">// EmojiData['url']</span>
      url: { <span class="hljs-keyword">default</span>: <span class="hljs-literal">null</span> }
    };
 },

 <span class="hljs-comment">// parse the initial content or/pasted clipboard, parse it to</span>
 <span class="hljs-comment">// see if the html-node matches to emoji-node schema</span>
 parseHTML() {
    <span class="hljs-keyword">return</span> [
      {
       <span class="hljs-comment">// all nodes should be identified with some selector,</span>
       <span class="hljs-comment">// in our case we use `data-node` our each node in schema</span>
       <span class="hljs-comment">// which is same as `Node.name`</span>
        tag: <span class="hljs-string">'span[data-node="emoji"]'</span>,
        <span class="hljs-comment">// get the required attribute from the node-schema html</span>
        getAttrs(node) {
          <span class="hljs-keyword">let</span> attrs: <span class="hljs-literal">false</span> | Record&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">any</span>&gt; = <span class="hljs-literal">false</span>;
          <span class="hljs-comment">// get the attributes character/emoji and fallback url</span>
          <span class="hljs-keyword">const</span> emoji = node.getAttribute(<span class="hljs-string">"data-emoji"</span>);
          <span class="hljs-keyword">const</span> url = node.getAttribute(<span class="hljs-string">"data-url"</span>);

          <span class="hljs-keyword">if</span> (emoji || url) {
            attrs = {
              emoji,
              url,
            };
          }

          <span class="hljs-keyword">return</span> attrs;
        },
      },
    ];
  },

  <span class="hljs-comment">// render the schema-node representation to html content</span>
 renderHTML({ HTMLAttributes, node }) {
    <span class="hljs-comment">// we need to know if the env supports the emoji</span>
    <span class="hljs-comment">// unicode char, if it doesn't we should render the fallback image</span>
    <span class="hljs-keyword">let</span> renderEmoji = <span class="hljs-literal">false</span>;

    <span class="hljs-keyword">const</span> isBrowserEnv = isBrowser();

    <span class="hljs-keyword">if</span> (isBrowserEnv) {
      <span class="hljs-comment">// it is very interesting concept how emoji supported is checked</span>
      <span class="hljs-comment">// on browser by rendering it on canvas and doing </span>
      <span class="hljs-comment">// some color checks, i'm using the package directly here</span>
      renderEmoji = isEmojiSupported(node.attrs.emoji);
    }

    <span class="hljs-keyword">const</span> { emoji, ...restHTMLAttributes } = HTMLAttributes;

    <span class="hljs-keyword">return</span> [
      <span class="hljs-comment">// root-node &lt;span data-node="emoji" data-emoji="🥵" data-url="..."&gt;</span>
      <span class="hljs-string">"span"</span>,
      mergeAttributes(restHTMLAttributes, {
        <span class="hljs-comment">// add all html equivalent attributes</span>
        <span class="hljs-string">"data-node"</span>: <span class="hljs-string">"emoji"</span>,
        <span class="hljs-string">"data-emoji"</span>: node.attrs.emoji,
        <span class="hljs-string">"data-url"</span>: node.attrs.url,
        <span class="hljs-comment">// styles to make sure emoji works as intended</span>
        <span class="hljs-comment">// font-family needs to be inorder as firefox differ from chrome</span>
        style: <span class="hljs-string">`user-select: text; font-family: "Twemoji Mozilla", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", "EmojiOne Color", "Android Emoji", sans-serif;`</span>,
      }),
      <span class="hljs-comment">// &lt;img src="..." fallback or custom emoji</span>
      [
        <span class="hljs-string">"img"</span>,
        {
          src: node.attrs.url,
          <span class="hljs-comment">// we will not show image fallback if env supports the emoji</span>
          <span class="hljs-comment">// also w=1em, h=1em ensures that fallback scales </span>
          <span class="hljs-comment">// with font-size of current text</span>
          style: <span class="hljs-string">`<span class="hljs-subst">${
            renderEmoji ? <span class="hljs-string">"display: none;"</span> : <span class="hljs-string">"display: inline-block;"</span>
          }</span> width: 1em; height: 1em;`</span>,
        },
      ],
      <span class="hljs-comment">// &lt;span&gt;🥵&lt;/span&gt;</span>
      [
        <span class="hljs-string">"span"</span>,
        {
          role: <span class="hljs-string">"img"</span>,
          <span class="hljs-comment">// render the image as inline-block</span>
          style: <span class="hljs-string">`<span class="hljs-subst">${renderEmoji ? <span class="hljs-string">"display: inline-block;"</span> : <span class="hljs-string">"display: none;"</span>}</span>`</span>,
        },
        node.attrs.emoji,
      ],
    ];
  },

  <span class="hljs-comment">// we should copy node always as character in clipboard</span>
  <span class="hljs-comment">// the node schema is specific to use and will not be recognised</span>
  <span class="hljs-comment">// in any other platform, so make sure you allways copy as unicode</span>
  renderText({ node }) {
    <span class="hljs-keyword">return</span> node.attrs.emoji;
  },

  <span class="hljs-comment">// allow to programatically insert the emoji</span>
  <span class="hljs-comment">// user should be able to insert emoji node from editor command</span>
  <span class="hljs-comment">// create `insertEmoji` command</span>
  addCommands() {
    <span class="hljs-keyword">return</span> {
      insertEmoji({ url, emoji }) {
        <span class="hljs-keyword">return</span> <span class="hljs-function">(<span class="hljs-params">{ editor, chain }</span>) =&gt;</span> {
          <span class="hljs-comment">// any `atomic` node faces difficulties while selecting</span>
          <span class="hljs-comment">// in tiptap editor, thus we insert dummy space to allow</span>
          <span class="hljs-comment">// selections to happen on #Text and in turn on emoji-node</span>
          <span class="hljs-keyword">const</span> shouldInsertSpace = shouldInsertSpaceAfterCurrentCursor(editor);

          <span class="hljs-keyword">return</span> chain()
            .insertContent({
              <span class="hljs-keyword">type</span>: <span class="hljs-string">"emoji"</span>,
              attrs: {

                url,
                emoji,
              },
            })
            <span class="hljs-comment">// if next position is alredy a space don't insert anything</span>
            <span class="hljs-comment">// else insert space for selection sake</span>
            .insertContent(shouldInsertSpace ? <span class="hljs-string">" "</span> : <span class="hljs-string">""</span>)
            .run();
        };
      },
    };
  },
});
</code></pre>
<p>You can checkout the code on <a target="_blank" href="https://github.com/vtechguys/tiptap-emoji-node/tree/main">my GitHub</a> for emoji node.</p>
<p>Now that we have created the emoji node, it is time to create the emoji picker. In my case I want the picker to be activated as soon as someone presses <code>:</code> and close when they select an emoji or press <code>:</code> back again.</p>
<p>Let’s get requirements clear for picker:</p>
<ol>
<li><p>Trigger on <code>:</code></p>
</li>
<li><p>Open a emoji list as grid in popup near the cursor.</p>
</li>
<li><p>Filter the emoji in the popup list as user types and show matching emojis.</p>
</li>
<li><p>If user matched on one emoji and press <code>:</code> insert that emoji by default let the user choose from the list otherwise.</p>
</li>
</ol>
<p>You can have your own emoji database from emoji-base, or for timebeing simpley use</p>
<pre><code class="lang-typescript">[
  {
    <span class="hljs-string">"shortcodes"</span>: [<span class="hljs-string">"grinning"</span>, <span class="hljs-string">"grinning_face"</span>],
    <span class="hljs-string">"emoji"</span>: <span class="hljs-string">"😀"</span>,
    <span class="hljs-string">"annotation"</span>: <span class="hljs-string">"grinning face"</span>
  },
  {
    <span class="hljs-string">"shortcodes"</span>: [<span class="hljs-string">"grinning_face_with_big_eyes"</span>, <span class="hljs-string">"smiley"</span>],
    <span class="hljs-string">"emoji"</span>: <span class="hljs-string">"😃"</span>,
    <span class="hljs-string">"annotation"</span>: <span class="hljs-string">"grinning face with big eyes"</span>
  }
]
</code></pre>
<p>To trigger popup on press of a characater we will use <a target="_blank" href="https://tiptap.dev/docs/editor/api/utilities/suggestion">tiptap-suggestion</a> extension and modify it to match our use case.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Extension } <span class="hljs-keyword">from</span> <span class="hljs-string">"@tiptap/react"</span>;
<span class="hljs-keyword">import</span> Suggestion, {
  SuggestionOptions <span class="hljs-keyword">as</span> NativeSuggestionOption
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@tiptap/suggestion"</span>;
<span class="hljs-comment">// my emoji-node package published as npm repo,</span>
<span class="hljs-comment">// same as what we have built above</span>
<span class="hljs-keyword">import</span> { EmojiNode, EmojiData } <span class="hljs-keyword">from</span> <span class="hljs-string">"@vtechguys/tiptap-emoji-node"</span>;
<span class="hljs-keyword">import</span> { isEmojiSupported } <span class="hljs-keyword">from</span> <span class="hljs-string">"is-emoji-supported"</span>;
<span class="hljs-comment">// the rendering depends on end user in my case i have rendred</span>
<span class="hljs-comment">// as simple dom of grid items.</span>
<span class="hljs-keyword">import</span> { filterEmoji, getRenderItems, RenderItemsProps } <span class="hljs-keyword">from</span> <span class="hljs-string">"./utils"</span>;

<span class="hljs-keyword">type</span> SuggestionOptions = Pick&lt;NativeSuggestionOption, <span class="hljs-string">"char"</span> | <span class="hljs-string">"command"</span>&gt;;

<span class="hljs-keyword">type</span> Emoji = EmojiData &amp; {
  search?: <span class="hljs-built_in">string</span>;
};

<span class="hljs-keyword">type</span> EmojiPickerOptions = {
  <span class="hljs-comment">// list of emojis from your database/json</span>
  emojis: Emoji[];
  <span class="hljs-comment">// default tiptap suggestion options</span>
  suggestion: SuggestionOptions;
  <span class="hljs-comment">// we we want database/json to be fetched at later instance</span>
  <span class="hljs-comment">// this saves resource loaded on first render</span>
  fetch?: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">Promise</span>&lt;Emoji[]&gt;;
  <span class="hljs-comment">// popup is using tippy so tippy config</span>
  tippy: RenderItemsProps[<span class="hljs-string">"tippy"</span>];
  <span class="hljs-comment">// callback to trigger whenever emoji is clicked</span>
  onEmojiSelected?: RenderItemsProps[<span class="hljs-string">"onEmojiSelected"</span>];
  classes: RenderItemsProps[<span class="hljs-string">"classes"</span>];
};

<span class="hljs-comment">/**
 add propperty to emoji if it is supported on current env
**/</span>
<span class="hljs-keyword">const</span> populateEmoji = <span class="hljs-function">(<span class="hljs-params">emojis: Emoji[]</span>) =&gt;</span> {
  emojis.forEach(<span class="hljs-function">(<span class="hljs-params">emoji</span>) =&gt;</span> {
    emoji.isSupported = isEmojiSupported(emoji.emoji);
  });

  <span class="hljs-keyword">return</span> emojis;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> EmojiPicker = Extension.create&lt;EmojiPickerOptions&gt;({
  name: <span class="hljs-string">"emoji-picker"</span>,

  <span class="hljs-comment">/**
   * Picker needs basic extension for rendering emoji node
   */</span>
  addExtensions() {
    <span class="hljs-keyword">return</span> [EmojiNode];
  },
  <span class="hljs-comment">/**
   We will store the emojis database as a list in  editor's client storage
  **/</span>
  addStorage() {
    <span class="hljs-keyword">return</span> {
      emojis: [],
    };
  },

  onCreate() {
    <span class="hljs-comment">/**
     * storage is initialized with emojis and make sure
     * emoji is populated with emoji with isSupported flag
     * the flag indicates what in the given list is supported
     */</span>
    <span class="hljs-built_in">this</span>.storage.emojis = populateEmoji(<span class="hljs-built_in">this</span>.options.emojis) || [];

    <span class="hljs-comment">/**
     * The init didn't provided emojis,
     * thus we will try to fetch from url
     */</span>
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.storage.emojis.length === <span class="hljs-number">0</span>) {
      <span class="hljs-built_in">this</span>.options.fetch?.()?.then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
        <span class="hljs-built_in">this</span>.storage.emojis = populateEmoji(data);
      });
    }
  },

  addOptions() {
    <span class="hljs-keyword">return</span> {
      tippy: {
       <span class="hljs-comment">// width of the popup</span>
        maxWidth: <span class="hljs-number">364</span>,
      },
      emojis: [],
      suggestion: {
       <span class="hljs-comment">// trigger char is :</span>
        char: <span class="hljs-string">":"</span>,
        command: <span class="hljs-function">(<span class="hljs-params">{ editor, range, props }</span>) =&gt;</span> {
          props.command({ editor, range, props });
        },
      },
      <span class="hljs-comment">// picker dom classes</span>
      classes: {
        root: <span class="hljs-string">"emoji-picker__container"</span>,
        emojiContainer: <span class="hljs-string">"emoji-picker__emoji"</span>,
        emojiImage: <span class="hljs-string">"emoji-picker__emoji__img"</span>,
        emojiChar: <span class="hljs-string">"emoji-picker__emoji__char"</span>,
      },
    };
  },

  addProseMirrorPlugins() {
    <span class="hljs-keyword">return</span> [
      Suggestion({
        editor: <span class="hljs-built_in">this</span>.editor,

        ...this.options.suggestion,

        items: <span class="hljs-function">(<span class="hljs-params">{ query }</span>) =&gt;</span> {
          <span class="hljs-comment">// when the user starts typing after triggering emoji</span>
          <span class="hljs-comment">// filter the matching emojis from the list</span>
          <span class="hljs-comment">// the retuned filtered emojis[] will be renderd in popup</span>
          <span class="hljs-keyword">return</span> filterEmoji(query, <span class="hljs-built_in">this</span>.storage.emojis);
        },
        <span class="hljs-comment">// don't allow user to type space</span>
        allowSpaces: <span class="hljs-literal">false</span>,
       <span class="hljs-comment">// anywhere in the text we should be able to trigger emoji</span>
        startOfLine: <span class="hljs-literal">false</span>,

        render: <span class="hljs-function">() =&gt;</span>
          <span class="hljs-comment">// from the returned filtered items render the list inside popup</span>
          getRenderItems({
            tippy: <span class="hljs-built_in">this</span>.options.tippy,
            editor: <span class="hljs-built_in">this</span>.editor,
            onEmojiSelected: <span class="hljs-built_in">this</span>.options.onEmojiSelected,
            classes: <span class="hljs-built_in">this</span>.options.classes,
          }),
      }),
    ];
  },
});
</code></pre>
<p>Implmentation of <code>filterEmoji</code> is upto you, I will show the render function which is responsible for rendering the emojis.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getRenderItems = <span class="hljs-function">(<span class="hljs-params">args: RenderItemsProps</span>) =&gt;</span> {
  <span class="hljs-comment">/**
   * Maintains the latest list of rendered items,
   * !Note: Should be updated first in every cycle of render
   */</span>
  <span class="hljs-keyword">let</span> currentItems: EmojiData[];

  <span class="hljs-keyword">let</span> component: ReturnType&lt;<span class="hljs-keyword">typeof</span> initNodeView&gt;;
  <span class="hljs-keyword">let</span> popup: <span class="hljs-built_in">any</span>;

  <span class="hljs-keyword">return</span> {
    onStart: <span class="hljs-function">(<span class="hljs-params">props: SuggestionProps</span>) =&gt;</span> {
      <span class="hljs-comment">// 1. update the current items first</span>
      currentItems = props.items;
      <span class="hljs-comment">// 2. init the node view</span>
      component = initNodeView(args);
      <span class="hljs-comment">// 3. init the popup, tippy</span>
      popup = tippy(<span class="hljs-string">"body"</span>, {
        getReferenceClientRect: props.clientRect <span class="hljs-keyword">as</span> GetReferenceClientRect,
        appendTo: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">document</span>.body,
        content: component.root,
        showOnCreate: <span class="hljs-literal">true</span>,
        interactive: <span class="hljs-literal">true</span>,
        trigger: <span class="hljs-string">"manual"</span>,
        placement: <span class="hljs-string">"bottom-start"</span>,
        maxWidth: args.tippy.maxWidth,
        zIndex: args.tippy.zIndex || <span class="hljs-number">2147483647</span>,
        ...args.tippy,
      });
      <span class="hljs-comment">// 4. render after init is completed</span>
      component.render(props);
    },

    onUpdate(props: SuggestionProps) {
      <span class="hljs-comment">// 1. update the list of items</span>
      currentItems = props.items;
      <span class="hljs-comment">// 2. render the items with updated props</span>
      component.render(props);
      <span class="hljs-comment">// 3. update popup</span>
      popup[<span class="hljs-number">0</span>].setProps({
        getReferenceClientRect: props.clientRect,
      });
    },

    onKeyDown(props: SuggestionKeyDownProps) {
      <span class="hljs-comment">/**
       * Esc are treated as escape from popup
       */</span>
      <span class="hljs-keyword">if</span> (props.event.key === <span class="hljs-string">"Escape"</span>) {
        popup[<span class="hljs-number">0</span>].hide();
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
      }

      <span class="hljs-comment">/**
       * Close the suggestion is user press `:` and there was only one matching element in list,
       * example `:cool` will filter and show  🆒  in picker popup list,
       * now as soon as user press `:` again close the popup and insert the matching emoji, here 🆒
       * as :cool: is short code for 🆒
       */</span>
      <span class="hljs-keyword">if</span> (props.event.key === <span class="hljs-string">":"</span> &amp;&amp; currentItems.length === <span class="hljs-number">1</span>) {
        args.editor
          .chain()
          .deleteRange(props.range)
          .insertEmoji(currentItems[<span class="hljs-number">0</span>])
          .run();
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
      }

      <span class="hljs-keyword">return</span> component.onKeyDown?.(props);
    },

    onExit(props: SuggestionProps) {
      popup[<span class="hljs-number">0</span>].destroy();
      component.destroy();
    },
  };
};
</code></pre>
<p>Our Native Javascript NodeView will look like:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">/**
 * Init the view of the item
 * @param args
 * @returns
 */</span>
<span class="hljs-keyword">const</span> initNodeView = <span class="hljs-function">(<span class="hljs-params">args: ViewArgs</span>) =&gt;</span> {
  <span class="hljs-comment">/**
   * record current render props
   */</span>
  <span class="hljs-keyword">let</span> renderProps: SuggestionProps | <span class="hljs-literal">null</span> = <span class="hljs-literal">null</span>;

  <span class="hljs-comment">/**
   * create the root level element
   */</span>

  <span class="hljs-keyword">const</span> root = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"div"</span>);
  root.classList.add(args.classes?.root || <span class="hljs-string">""</span>);

  <span class="hljs-comment">/**
   * create click event on emoji popup root, select and insert the 
   * clicked emoji
   */</span>
  <span class="hljs-keyword">const</span> clickBinding = addEvent(root, <span class="hljs-string">"click"</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {

    <span class="hljs-keyword">if</span> (!renderProps) {
      <span class="hljs-keyword">return</span>;
    }


    <span class="hljs-keyword">let</span> emoji = <span class="hljs-literal">null</span>;
    <span class="hljs-comment">// find the clicked emoji</span>
    <span class="hljs-comment">// find the position(index) in the list</span>
    <span class="hljs-keyword">const</span> position = <span class="hljs-built_in">Number</span>(((event.target <span class="hljs-keyword">as</span> HTMLElement)?.closest(<span class="hljs-string">"[data-position]"</span>) <span class="hljs-keyword">as</span> HTMLElement)?.dataset?.position);
    <span class="hljs-comment">// get the emoji at the index</span>
    <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">Number</span>.isNaN(position)) {
      emoji = renderProps?.items?.[position];
    }


    <span class="hljs-keyword">if</span> (!emoji) {
      <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-comment">// the emoji selected callback is called and if the callback</span>
    <span class="hljs-comment">// returns true we assume the insertion is being handled by callback</span>
    <span class="hljs-comment">// else we will do the insertion</span>
    <span class="hljs-keyword">const</span> handled = args.onEmojiSelect?.(event, {
        range: renderProps.range,
        editor: renderProps.editor,
        emoji,
      });

    <span class="hljs-keyword">if</span> (!handled) {
      renderProps.
          editor?.chain?.()
      <span class="hljs-comment">// as user can type after :</span>
      <span class="hljs-comment">// which is received as query to filter emoji list</span>
      <span class="hljs-comment">// we need to remove this query text before insertion emoji</span>
      <span class="hljs-comment">// the text index range is provided by TipTap suggestion plugin</span>
          ?.deleteRange(renderProps.range)
      <span class="hljs-comment">// insert the emoji node using the command that we created</span>
          ?.insertEmoji?.(emoji)?.run?.();
    }

  });

  <span class="hljs-comment">/**
   create each emoji element
    &lt;span data-position="index"&gt;
        &lt;img [src, alt] /&gt; (fallback if emoji is not supported)
        &lt;span&gt; (emoji-unicode char)
   */</span>
  <span class="hljs-keyword">const</span> createEmoji = <span class="hljs-function">(<span class="hljs-params">emoji: EmojiData, index: <span class="hljs-built_in">number</span></span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> emojiContainer = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"span"</span>);
    emojiContainer.classList.add(args.classes?.emojiContainer || <span class="hljs-string">""</span>);

    emojiContainer.setAttribute(<span class="hljs-string">"data-position"</span>, <span class="hljs-string">`<span class="hljs-subst">${index}</span>`</span>);

    <span class="hljs-keyword">const</span> isSupported = emoji.isSupported;

    <span class="hljs-keyword">const</span> img = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"img"</span>);
    img.classList.add(args.classes?.emojiImage || <span class="hljs-string">""</span>);
    img.setAttribute(<span class="hljs-string">"src"</span>, emoji.url || <span class="hljs-string">""</span>);
    img.setAttribute(<span class="hljs-string">"alt"</span>, <span class="hljs-string">"Emoji of "</span> + emoji.annotation);
    img.style.display = isSupported ? <span class="hljs-string">"none"</span> : <span class="hljs-string">"inline-block"</span>;

    <span class="hljs-keyword">const</span> char = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"span"</span>);
    img.classList.add(args.classes?.emojiChar || <span class="hljs-string">""</span>);

    char.setAttribute(<span class="hljs-string">"role"</span>, <span class="hljs-string">"img"</span>);
    char.ariaLabel = emoji.annotation;
    char.style.display = isSupported ? <span class="hljs-string">"inline-block"</span> : <span class="hljs-string">"none"</span>;
    char.appendChild(<span class="hljs-built_in">document</span>.createTextNode(emoji.emoji));

    emojiContainer.append(img, char);

    <span class="hljs-keyword">return</span> emojiContainer;
  };

  <span class="hljs-comment">// a custom nodeview object</span>

  <span class="hljs-keyword">return</span> {
    root,
    <span class="hljs-comment">/**
     * render the view with given props
     */</span>
    render(props: SuggestionProps) {
      renderProps = props;

      root.innerHTML = <span class="hljs-string">""</span>;

      <span class="hljs-keyword">const</span> emojis = props.items.map(<span class="hljs-function">(<span class="hljs-params">emoji, index</span>) =&gt;</span>
        createEmoji(emoji, index)
      );
      root.append(...emojis);
    },
    <span class="hljs-comment">/**
     * destroy view
     */</span>
    destroy() {
      renderProps = <span class="hljs-literal">null</span>;
      clickBinding?.destroy();
      root.remove();
    },

    onKeyDown(props: SuggestionKeyDownProps) {
      <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> move between emojis in the list</span>

      <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    },
  };
};
</code></pre>
<p>Once you have all that in place, you will have a emoji picker. You may want to go through the emoji picker code on my github <a target="_blank" href="https://github.com/vtechguys/tiptap-emoji-picker/blob/main/README.md">@vtechguys/tiptap-emoji-picker</a></p>
<p>Stay tuned for more such tiptap extensions blog post.</p>
]]></content:encoded></item><item><title><![CDATA[Scalable state management in React]]></title><description><![CDATA[State management is always a problem to solve in big applications. Many design patterns and libraries emerge to solve some issues by proposing different ways of doing things. In this article, our main focus is on the philosophy of managing your state...]]></description><link>https://aniketjha.dev/scalable-state-management-in-react</link><guid isPermaLink="true">https://aniketjha.dev/scalable-state-management-in-react</guid><category><![CDATA[State Management ]]></category><category><![CDATA[React]]></category><category><![CDATA[Microfrontend]]></category><category><![CDATA[scalability]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[ReactHooks]]></category><dc:creator><![CDATA[Aniket Jha]]></dc:creator><pubDate>Sat, 06 Jul 2024 19:24:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1720293640205/ff946706-51f0-47db-8246-2e21b9263aab.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>State management is always a problem to solve in big applications. Many design patterns and libraries emerge to solve some issues by proposing different ways of doing things. In this article, our main focus is on the philosophy of managing your state in applications; most of the things are library-independent.</p>
<h2 id="heading-do-you-need-a-state-management-library"><strong>Do you need a state management library?</strong></h2>
<p>You don’t realize it, but you may often skip using any state management library in your application. Native state hooks in React and some composition patterns can accomplish the majority of things.</p>
<h3 id="heading-do-you-want-to-communicate-changes-from-one-part-of-the-tree-to-another"><strong>Do you want to communicate changes from one part of the tree to another?</strong></h3>
<p>Pull the state up to a common parent and pass it via props or context.</p>
<h3 id="heading-does-my-state-have-too-many-properties"><strong>Does my state have too many properties?</strong></h3>
<p>useReducer is very powerful; you should pay attention to native stuff.</p>
<h3 id="heading-i-have-asynchronous-stuff-going-on-in-my-app"><strong>I have asynchronous stuff going on in my app.</strong></h3>
<p>useQuery, useSWR, and useEffect are perfect candidates to solve your problem.</p>
<p>I’m not against state management libraries, but once you do a <code>npm i xyz</code>, you are bound to think in their paradigm, and now you want the library to do everything for you. Things that don’t make sense in the state will be moved to the state; things that are derived from states will see their property in the state. You end up chaining yourself to thinking only in the paradigm of that library.</p>
<h2 id="heading-questions-that-matter"><strong>Questions that matter</strong></h2>
<ul>
<li><p>I have a deeply nested leaf item that modifies and affects the entire app.</p>
</li>
<li><p>I have too many features that are dependent on each other.</p>
</li>
<li><p>I have other feature states spread out in my own feature, coupling things.</p>
</li>
<li><p>I find it difficult to communicate between features.</p>
</li>
</ul>
<h1 id="heading-philosophy"><strong>Philosophy</strong></h1>
<p>A product manager tries to pack in many features in their application; however, that may be good for the user but is a horror for developers. If you have such a project manager, I feel you, bro! 🥲</p>
<p>But as developers, it is our responsibility that feature addition and deletion should be plug-and-play; even your project manager should be able to do it by pressing the harmless* button, and your code should ensure that it is harmless.</p>
<h2 id="heading-mind-your-own-business"><strong>Mind your own business</strong></h2>
<p>Your feature should always be independent of any other feature in the app.</p>
<p>It should not directly poke its nose into the business logic of other features and strictly remind them to “Mind their own business” when they try to poke their nose into your stuff.</p>
<p>When you develop something, make sure you write it in such a way that it can run in <strong><em>isolation</em></strong>, that is the core of philosophy.</p>
<p>Make your code in such a way that if one feature speaks English, the other feature should speak Chinese, What I’m stressing is that the features should not have any knowledge of each other; they should not be able to talk to each other <strong><em>directly.</em></strong></p>
<p>But you need to send messages across, and that is why you need a mediator, translator, or <strong><em>orchestrator.</em></strong></p>
<p>Say I'm building something similar to notion</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720292863423/ab17b7e1-de38-45a1-b1ed-d0bef642ded7.png" alt class="image--center mx-auto" /></p>
<p>I see two main items:</p>
<ul>
<li><p>Sidebar</p>
</li>
<li><p>Editor</p>
</li>
</ul>
<p>When a page is clicked in the sidebar, it opens up in the editor.</p>
<p>When the editor heading changes, the text also changes in the sidebar.</p>
<p>The context menu in the sidebar allows you to rename the editor headline.</p>
<p><strong>Sidebar state:</strong></p>
<pre><code class="lang-javascript">state = [
  { 
    <span class="hljs-attr">id</span>: string; <span class="hljs-comment">// uniq page id</span>
    label: string; <span class="hljs-comment">// title of the page</span>
    value: string; <span class="hljs-comment">// page value</span>
  },
  ...
]
</code></pre>
<p><strong>Editor state:</strong></p>
<pre><code class="lang-javascript">state = {
    <span class="hljs-attr">id</span>: string;
    title: string;
    content: [
        {
            <span class="hljs-attr">tag</span>: string;
            content: []
        },
        ...
    ]
}
</code></pre>
<p>Note: Each has its state and not a common state so when I update text in the sidebar, that will update its own state and editor state.</p>
<p>A naive implementation would look like this:</p>
<pre><code class="lang-javascript">onRename = <span class="hljs-function">() =&gt;</span> {
 <span class="hljs-comment">// update the state in sidebar</span>
  sidebarDispatch({ 
      <span class="hljs-attr">type</span>: <span class="hljs-string">'sidebar/update_item'</span>, 
        <span class="hljs-attr">payload</span>: { 
            <span class="hljs-attr">id</span>: <span class="hljs-string">'..'</span>, 
            <span class="hljs-attr">title</span>: <span class="hljs-string">'...'</span> 
        } 
    });

    <span class="hljs-comment">// update the same in editor</span>
    editorDispatch({
        <span class="hljs-attr">type</span>: <span class="hljs-string">'editor/update_text'</span>,
        <span class="hljs-attr">payload</span>: {
           <span class="hljs-attr">title</span>: <span class="hljs-string">'...'</span>
        }
    })
}
</code></pre>
<p>This <code>onRename</code> function would be present in both modules, i.e., editor and sidebar, but this is what causes coupling. Although we want to do exact same thing but not spread dispatch across modules,.</p>
<p>We will pull this into this logic<code>globalOrchestrator</code>, which acts as a mediator between the two. It may look like this:</p>
<pre><code class="lang-javascript">globalOrchestrator({ <span class="hljs-attr">type</span>: <span class="hljs-string">'rename'</span>, <span class="hljs-attr">paylod</span>: { <span class="hljs-attr">id</span>: <span class="hljs-string">'..'</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">'...'</span> } })
</code></pre>
<p>The <code>globalOrchestrator</code> would exactly consume dispatches but abstract them in a way that two modules only know the <code>globalOrchestrator</code>.</p>
<p>The editor thinks that doing so <code>globalOrchestrator &gt; rename</code> will update the editor's own text and the editor states, it does not know the sidebar.</p>
<p>The same is true of the story of the sidebar, where it only knows <code>globalOrchestrator &gt; rename</code> updates its own state.</p>
<p>That is how cross-communication happens and every feature has its own business in application.</p>
<p>We have eliminated <strong><em>coupling</em></strong>, you may not realize it but let’s say in the future you need to remove the sidebar as a feature as a whole What you will do is delete the sidebar directory and remove the sidebar dispatch from <code>globalOrchestrator &gt; rename</code></p>
<h2 id="heading-never-show-your-true-self"><strong>Never show your true self</strong></h2>
<p>You, as a feature, should always… always create abstractions over your internal <em>state, hooks, dispatch, useSelector/useAtom/useSlice.</em></p>
<ul>
<li>Never expose your entire state; expose atoms or slices of state in hooks.</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> useSidebarOpenState = <span class="hljs-function">() =&gt;</span> {
 <span class="hljs-comment">// 1. mark internal state as unsafe</span>
 <span class="hljs-comment">// 2. your lib specific way to get slice/atom</span>
 <span class="hljs-keyword">return</span> useSidebarState__UNSAFE(<span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> state.open);
}
</code></pre>
<ul>
<li>Never expose dispatches or actions</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> useSidebarOpenDispatch = <span class="hljs-function">() =&gt;</span> {
 <span class="hljs-keyword">const</span> dispatch = useSidebarDispatch__UNSAFE();
 <span class="hljs-keyword">const</span> open = <span class="hljs-function">() =&gt;</span> {
     dispatch(sidebarOpenAction());
 };
 <span class="hljs-keyword">return</span> open;
}
</code></pre>
<ul>
<li>You may choose to combine the two</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> useSidebarOpen = <span class="hljs-function">() =&gt;</span> [useSidebarOpenState(), useSidebarOpenAction()]
</code></pre>
<ul>
<li>Expose as little as possible, create and derive values in hooks itself.</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> useSidebarHasItemState = <span class="hljs-function">() =&gt;</span> {
 <span class="hljs-comment">// instead of having items exposed we should </span>
 <span class="hljs-comment">// Start with exactly what was required</span>
 <span class="hljs-comment">// yes you may need all of the items but that is diff</span>
 <span class="hljs-keyword">return</span> useSidebarState__UNSAFE(<span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> state.items.length &gt; <span class="hljs-number">0</span>);
}
</code></pre>
<ul>
<li>Binding at the top</li>
</ul>
<p>Structure your code in such a way that you create all global bindings, handlers, and complex logic at the root of the feature component and make individual nodes of the tree pure, dumb, and presentational components.</p>
<pre><code class="lang-typescript">sidebar
 |____ components
 |        |___ search
 |        |___ section
 |               |___ Header.tsx
 |               |___ ItemList.tsx
 |
 |____ hooks
 |      |___ useInfiniteScroll.ts
 |
 |____ views
 |       |___ Root.tsx
 |
 |____ Orchestrator.ts
</code></pre>
<p>The above structure is how we would like to visualize and lay out our features.</p>
<ul>
<li><p>Anything inside of components has to be pure and driven by props and may have internal <code>useState</code>, but should in no way be bound to any <em>global/environmental state/handler/actions</em>.</p>
</li>
<li><p>Anything inside of hooks is hooks used inside our feature directory or may be exposed to the outside world, these may contain hooks with global bindings and pure hooks with internal usage.</p>
<p>  Only hooks with internal usage may be used in the components dir, any hook with global bindings will not be used in the components dir.</p>
<p>  Usually, it is a good idea to localise internal hooks within the component dir,</p>
<p>  for example:<br />  <code>useInfiniteScroll</code> load sidebar items on the scroll can be within <code>sidebar/components/section</code> and used inside of <code>ItemList.tsx</code>.</p>
</li>
<li><p>Anything inside of views creates bindings to the environmental state and is distributed as props to underlying components. These are the perfect sites to consume global state and simplify handlers.</p>
<p>  Say our sidebar had two tabs, admin and user, where if switched they would render their own tree in the sidebar. They can have their individual roots in<br />  <code>views</code> dir.</p>
<p>  A <code>Root</code> is the mounting point of the feature component; it may branch into several roots, for example <code>AdminRoot</code> or <code>UserRoot</code> with only the purpose of simplifying the underlying tree and branching slowly into a simpler tree. Each branch of Root tries to simplify stuff so that underlying trees are super simple.</p>
</li>
<li><p>These roots are where we may consume our global-bound hooks, handlers, and utils, everything should be passed on as props. Props drilling may be an issue but remember that props usually tend to redistribute themselves as we nest and if 10 props were passed on during the 4–5th nesting or drilling, only 2–3 props may be required. If too props drilling too much, use context here.</p>
</li>
<li><p>Note that it is not advised to directly bind or use global utils inside components but you may choose to wrap those in a SidebarOrchestrator that will exist to bind global to sidebar local, use this Orchestrator from props, create a SidebarOrchestrator hook, or use simple utils; that is up to you to decide.</p>
</li>
</ul>
<p>In the future, you could just re-export to npm and use the sidebar with your own views and bindings in a different application or for your sister company.</p>
]]></content:encoded></item><item><title><![CDATA[Scale with rate limiters]]></title><description><![CDATA[Availability and reliability are important parts of systems; if you are exposing an API, it should be available and reliable to consumers.
You must have experienced this when you grew your API endpoints and received more traffic. It is okay as the bu...]]></description><link>https://aniketjha.dev/scale-with-rate-limiters</link><guid isPermaLink="true">https://aniketjha.dev/scale-with-rate-limiters</guid><category><![CDATA[System Architecture]]></category><category><![CDATA[System Design]]></category><category><![CDATA[ratelimit]]></category><category><![CDATA[Redis]]></category><category><![CDATA[AWS]]></category><dc:creator><![CDATA[Aniket Jha]]></dc:creator><pubDate>Sat, 11 May 2024 07:58:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/WPrTKRw8KRQ/upload/6ba3384d941f04c7611d042f63d69f11.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Availability and reliability are important parts of systems; if you are exposing an API, it should be available and reliable to consumers.</p>
<p>You must have experienced this when you grew your API endpoints and received more traffic. It is okay as the business grows, but the growth brings bad actors into the system, and those actors may send too many requests and slow down your systems, or you may entirely shut them down.</p>
<p>Rate-limiting helps you solve the following:</p>
<ol>
<li><p>A bad user may send loads of requests, which should not affect any genuine user.</p>
</li>
<li><p>A user is sending you low-priority requests that are blocking high-priority requests. The system prioritizes high-priority requests over low-priority requests. This is called load shedding.</p>
</li>
<li><p>Sometimes, if the system is wrong internally (a resource crunch) and you cannot serve all your regular traffic, you may want to drop low-priority requests in favor of high-priority requests.</p>
</li>
</ol>
<p>Some common types of rate limiters are:</p>
<ul>
<li><p>Request rate limiter</p>
</li>
<li><p>Concurrent rate limiter</p>
</li>
<li><p>Fleet rate limiter</p>
</li>
<li><p>Worker utilization load shedder</p>
</li>
</ul>
<h3 id="heading-request-rate-limiter">Request Rate Limiter</h3>
<p>A rate limiter that limits requests for a user to N times per second. Usually, it is put per API, and the user is trained to send only limited requests per second for that API.  </p>
<p>For example, a user can only log in 5 times per minute.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Limit user to 5 requests in 5 minutes (5 * 60 seconds)</span>
<span class="hljs-meta">@RateLimit</span>({ threshold: <span class="hljs-number">5</span>, duration: <span class="hljs-number">5</span> * <span class="hljs-number">60</span> })
<span class="hljs-meta">@Post</span>(<span class="hljs-string">'/login'</span>)
</code></pre>
<p>What the above <code>@RateLimiter</code> decorator will do is limit a user to being able to log in only 5 times in a minute and reject with 429 if the user tries to log in more than 5 times. Depending on the implementation, it may follow any rate limiter algorithm, for example, token bucket [link here].</p>
<p>API rate limiter will save you most of the time, as these are usually triggered in any system. They also save API endpoints against rouge scripts, which has the potential to bring down the system. It is a good idea to keep some values of <code>threshold</code> and <code>duration</code> in production and development to prevent any surprises.</p>
<p>Websites like Amazon host flash sales where rate limits are relaxed and it is allowed to be leaky, i.e., burst briefly for a short period of time, that may be included in the implementation.</p>
<p><img src="https://images.ctfassets.net/fzn2n1nzq965/70aRVdIQ9Hhbr1wV9NPPDn/c9873fea1fb540a1b5ed9d9eb594549e/image.png?w=1620&amp;q=80" alt="Blog &gt; Rate Limiters &gt; Graph 1" /></p>
<blockquote>
<p>API Rate limiters, limits users to a maximum threshold of request per second.</p>
</blockquote>
<h3 id="heading-concurrent-rate-limiter">Concurrent rate limiter</h3>
<p>All API endpoints are not the same; some are slow and resource-hungry. Hitting the rate limit on such APIs affects the overall system performance, slowing down every low CPU usage API.</p>
<p>API level rate limits safeguard individual APIs, but this rate limiter makes sure to safeguard a set of APIs together to keep the system running at acceptable performance.</p>
<p>Current rate limiter: "You can only request 50 requests in progress at the same time.".<br />API Rate Limiter "You can send 1000 requests to our API endpoint."</p>
<p>It also forces users to think about how to manage the API requests.</p>
<p><img src="https://images.ctfassets.net/fzn2n1nzq965/6n0cFumdlNxMYdkfdz0JRu/24c589e3516573fb72068d8d35a7f3ef/image.png?w=1620&amp;q=80" alt="Blog &gt; Rate limiters &gt; Graph 2" /></p>
<blockquote>
<p>Concurrent rate limiter, manage resource-contention for CPU intensive API endpoints.</p>
</blockquote>
<h3 id="heading-fleet-usage-load-shedder">Fleet usage load shedder</h3>
<p>Load shedder rate limiting, sheds the load of low-priority endpoints by reserving a fixed fraction of resources to be always available to serve high-priority requests.</p>
<p>For say, it is like reserving 20% of our resources for high-priority requests and low-priority requests get 80% of system resources. In case of increased loads because of low-priority requests, we make sure that we don't compromise with percentage of resources allocated to high-priority requests. So low-priority requests will be dropped if it tries to cross 80% resource allocation with a 503.</p>
<p><img src="https://images.ctfassets.net/fzn2n1nzq965/70nvphdGeNMKHRsoJIsFFq/889af231f8ec95f95b640baaa629b455/image.png?w=1620&amp;q=80" alt="Blog &gt; Rate limiters &gt; Graph 3" /></p>
<blockquote>
<p>Fleet usage load shedder, make sure there are always enough resources for critical high-priority requests.</p>
</blockquote>
<h3 id="heading-worker-utilization-load-shedder">Worker utilization load shedder</h3>
<p>API services are served by a set of worker machines that independently receive and respond to requests. In case of increased loads when many requests are getting queued up on a worker, that worker may choose to drop a low-priority request in favor of any high-priority request in the queue. Worker sheds low-priority load as its utilization limits are challenged.</p>
<p>This is the last defense against increased traffic loads and is rarely triggered, maybe only in major incidents.</p>
<p>As an example, the API endpoints can be categorized in the following fashion:</p>
<ol>
<li><p>Critical request</p>
</li>
<li><p>Post request</p>
</li>
<li><p>Get request</p>
</li>
<li><p>Test script request</p>
</li>
</ol>
<p>Track the load and utilization of the worker and when we see it is getting challenged and many requests are being queued, the worker will start shedding requests from the bottom i.e requests from test script or automation environments are dropped first with 503, and we go up in the list as required.</p>
<p>It is important to bring back dropped requests with delay, as it may again cause issues to be brought back immediately.  </p>
<p>The idea here is to keep on shedding low-priority requests and trying our best to serve critical or high-priority requests as long as possible without a system shutdown, as soon as the incident is resolved we can slowly bring back traffic as per priority order to serve them back again.</p>
<p><img src="https://images.ctfassets.net/fzn2n1nzq965/5dU2JWBEVCh1kXHlKWakqw/3413cd572b53d2af0ae432dcc90e9585/image.png?w=1620&amp;q=80" alt="Blog &gt; Rate limiters &gt; Graph 4" /></p>
<blockquote>
<p>Worker utilization load shedders reserve workers for critical requests.</p>
</blockquote>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Rate Limiters are the most reliable way to accurately scale your API endpoints. Start small from the API level rate limit and gradually add others when needed.</p>
<p>In the real world, there are many rate limiter implementations that operate on different layers (middleware, application layer, IP layer). There are many different algorithms that rate limiters implement, keeping usage counts in Redis or something similar.</p>
<p>Depending on the scale of the company rate limiter can be in the API gateway, middlewares, or application layer. In any scenario, we should make sure if the rate limiter itself is down it shouldn't affect API as it is.</p>
<p>Intent should be relayed to rate limited/ throttled users, whether a service it is 429 or 503.</p>
<p>Keep metrics up to make sure you are not rejecting genuine requests and tune limits accordingly.</p>
]]></content:encoded></item><item><title><![CDATA[Optimize JavaScript, simple trick and techniques - Part 1]]></title><description><![CDATA[When I come across a huge codebase, I often feel that it can be optimised without changing the core of the programme. I'm listing a set of techniques that I have found useful in the past. In computers, every solution has a trade-off; mostly, performa...]]></description><link>https://aniketjha.dev/optimize-javascript-simple-trick-and-techniques-part-1</link><guid isPermaLink="true">https://aniketjha.dev/optimize-javascript-simple-trick-and-techniques-part-1</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[optimization]]></category><category><![CDATA[tips]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Aniket Jha]]></dc:creator><pubDate>Wed, 24 Apr 2024 15:40:40 GMT</pubDate><content:encoded><![CDATA[<p>When I come across a huge codebase, I often feel that it can be optimised without changing the core of the programme. I'm listing a set of techniques that I have found useful in the past. In computers, every solution has a trade-off; mostly, performance optimisation comes with a trade-off of reliability, but if it saves you significant resources, you may want to make a trade-off.</p>
<h3 id="heading-avoid-string-comparisons">Avoid string comparisons</h3>
<p>JavaScript authors attempt to hide complexities, and one such complexity is hidden behind <code>===</code> operator. In native languages like C, you get a <code>strcmp</code> function that iterates over string length and compares characters on each index, This complexity of iterating over the string is hidden behind a simple looking <code>===</code> operator.</p>
<p>Consider the following examples:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Example: 1 String Compare</span>

<span class="hljs-built_in">enum</span> <span class="hljs-built_in">Number</span> {
  EVEN = <span class="hljs-string">"EVEN"</span>,
  ODD = <span class="hljs-string">"ODD"</span>
}

<span class="hljs-comment">// String compare</span>
<span class="hljs-keyword">let</span> count = <span class="hljs-number">0</span>;
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">1000000</span>; i++) {
 <span class="hljs-keyword">const</span> label = i % <span class="hljs-number">2</span> === <span class="hljs-number">0</span> ? <span class="hljs-built_in">Number</span>.EVEN : <span class="hljs-built_in">Number</span>.ODD;
 <span class="hljs-comment">// "EVEN" === "EVEN"</span>
 <span class="hljs-comment">// "ODD" === "EVEN"</span>
 <span class="hljs-comment">// 1. iterate over string to compare</span>
 <span class="hljs-comment">// 2. pass by ref: mem lookups</span>
 <span class="hljs-keyword">if</span> (label === <span class="hljs-built_in">Number</span>.EVEN) {
    count += <span class="hljs-number">1</span>;
 }
}
</code></pre>
<p>The above code is a comparison of strings, which requires iteration over string length. Also, to a JS developer, the strings are passed by value, but internally, the strings in the <strong>engine</strong> are passed by reference, and those are stored in the <strong>string pool</strong>, i.e., the heap, which requires a memory lookup on each step. However, in the example below, we are using intergers, which are passed by value.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Example: 2 Integer compare</span>

<span class="hljs-built_in">enum</span> <span class="hljs-built_in">Number</span> {
  EVEN = <span class="hljs-number">0</span>,
  ODD = <span class="hljs-number">1</span>
}

<span class="hljs-comment">// String compare</span>
<span class="hljs-keyword">let</span> count = <span class="hljs-number">0</span>;
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">1000000</span>; i++) {
 <span class="hljs-keyword">const</span> label = i % <span class="hljs-number">2</span> === <span class="hljs-number">0</span> ? <span class="hljs-built_in">Number</span>.EVEN : <span class="hljs-built_in">Number</span>.ODD;
 <span class="hljs-comment">// 0 === 0</span>
 <span class="hljs-comment">// 1 === 0</span>
 <span class="hljs-comment">// 1. simple byte integer compare</span>
 <span class="hljs-keyword">if</span> (label === <span class="hljs-built_in">Number</span>.EVEN) {
    count += <span class="hljs-number">1</span>;
 }
}
</code></pre>
<h3 id="heading-avoid-different-shapes">Avoid different shapes</h3>
<p>JavaScript engines are optimised for same-shaped objects. Object <code>{ x, y }</code> and <code>{ y, x }</code> are of different shapes and thus are not very well optimised. In the case of many properties, the more variation an individual object has, the more wild it looks to engine and less optimisation kicks in.</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">add</span>(<span class="hljs-params">a, b</span>) </span>{
    <span class="hljs-keyword">return</span> {
        x: a.x + b.x,
        y: a.y + b.y
    }
}

<span class="hljs-keyword">const</span> a = { x: <span class="hljs-number">10</span>, y: <span class="hljs-number">5</span> };
<span class="hljs-keyword">const</span> b = { y: <span class="hljs-number">11</span>, x: <span class="hljs-number">6</span> }; <span class="hljs-comment">// shape of a and b are diff</span>
<span class="hljs-comment">// had `b` been { x, y } shape would be same and optimised</span>
</code></pre>
<p>Use the factory function to create objects that will ensure that they have the same shapes.</p>
<h3 id="heading-avoid-array-and-object-methods">Avoid Array and Object methods</h3>
<p>Belive me I love functional programming but my standards vary a bit. No matter how much I love <code>.map, .filter, .reduce</code> , if I see consuemtive usage of array methods, I will try to write it in an imperative way.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> result = [<span class="hljs-number">1.5</span>, <span class="hljs-number">3.5</span>, <span class="hljs-number">5.0</span>]
    .map(<span class="hljs-function">(<span class="hljs-params">n</span>) =&gt;</span> <span class="hljs-built_in">Math</span>.round(n))
    .filter(<span class="hljs-function"><span class="hljs-params">n</span> =&gt;</span> n % <span class="hljs-number">2</span>)
    .reduce(<span class="hljs-function">(<span class="hljs-params">a, n</span>) =&gt;</span> a + n, <span class="hljs-number">0</span>);
</code></pre>
<p>The problem is that it creates a new array each time, and multiple iterations happen on the array. I'm okay with writing new imperative code and putting it in a function as below.</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getRoundedEvenSum</span>(<span class="hljs-params">array</span>) </span>{
 <span class="hljs-keyword">let</span> sum = <span class="hljs-number">0</span>;

 <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; array.length; i++) {
   <span class="hljs-keyword">const</span> num = array[i];

   <span class="hljs-keyword">const</span> roundedNum = MAth.round(num);

   <span class="hljs-keyword">if</span> (roundedNum % <span class="hljs-number">2</span> === <span class="hljs-number">0</span>) { 
    sum += roundedNum;
   }  
 }

 <span class="hljs-keyword">return</span> sum;
}

<span class="hljs-comment">// complexity is being one function </span>
<span class="hljs-comment">// and it is still okishly readable</span>
</code></pre>
<p>same fate occurs<code>Object.values</code>, <code>Object.keys</code> and <code>Object.enteries</code> they creates new array in memory, which can be costly as an object grows.</p>
<h3 id="heading-nested-objects">Nested objects</h3>
<p>Usually, it is good idea to avoid nested objects and accesseing deeply nested properties. Caching the nested object keys early can help reduce nested lookups. Although engines are good at it, it may cost you. The same way JS proxies are a bit more heavy on lookups, try to avoid them if you can.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> nested = { a: { b: { c: { x: <span class="hljs-number">10</span>, y: <span class="hljs-number">11</span> } } } };

<span class="hljs-comment">// costly</span>
loop many times {
 nested.a.b.c.x + nested.a.b.c.y
}

<span class="hljs-comment">// cache early</span>
<span class="hljs-keyword">const</span> x = nested.a.b.c.x; 
<span class="hljs-keyword">const</span> y = nested.a.b.c.y;
loop many times {
 nested.a.b.c.x + nested.a.b.c.y
}
</code></pre>
<p>Let's understand these very well and follow up in our next article. Stay tuned more to come in series.</p>
]]></content:encoded></item><item><title><![CDATA[Creating component variants with ease]]></title><description><![CDATA[There are times when you are writing your UI component and want to add style variants to it. A button component can be a "primary" button with a "blue" background or a "secondary" button with an "orange" background. If I asked you to create a button ...]]></description><link>https://aniketjha.dev/creating-component-variants-with-ease</link><guid isPermaLink="true">https://aniketjha.dev/creating-component-variants-with-ease</guid><category><![CDATA[classes]]></category><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[CSS in JS]]></category><category><![CDATA[React]]></category><category><![CDATA[CSS]]></category><dc:creator><![CDATA[Aniket Jha]]></dc:creator><pubDate>Wed, 24 May 2023 04:42:24 GMT</pubDate><content:encoded><![CDATA[<p>There are times when you are writing your UI component and want to add style variants to it. A button component can be a "primary" button with a "blue" background or a "secondary" button with an "orange" background. If I asked you to create a button that can take an <code>intent</code> prop and render itself as a "primary" blue button or a "secondary" orange button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1684901652651/16304d00-0817-47e3-86a5-02f77bdec44d.png" alt class="image--center mx-auto" /></p>
<p>You would be writing ugly if-else statements to match the styles for the <code>intent</code> variant. Something like the following may be your code:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1684902141644/a70aa78c-370c-46d9-ac3f-2ad44d0d9972.png" alt class="image--center mx-auto" /></p>
<p>That may not look very ugly but imagine as the number of variants grows and there are values, you will have to put a lot of ugly if-else statements for styling only.</p>
<h3 id="heading-vtechguysvshttpsgithubcomvtechguysvs"><a target="_blank" href="https://github.com/vtechguys/vs">@vtechguys/vs</a></h3>
<p>Let me introduce you to an <a target="_blank" href="https://www.npmjs.com/package/@vtechguys/vs">npm library</a> that will do all that for you.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { GetVariantProps, vs } <span class="hljs-keyword">from</span> <span class="hljs-string">"@vtechguys/vs"</span>;
<span class="hljs-keyword">import</span> clsx <span class="hljs-keyword">from</span> <span class="hljs-string">"clsx"</span>;
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./styles.css"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> button = vs({
  base: <span class="hljs-string">"btn"</span>,
  variants: {
    intent: {
      primary: <span class="hljs-string">"btn-intent--primary"</span>,
      secondary: <span class="hljs-string">"btn-intent--secondary"</span>
    },
    size: {
      small: <span class="hljs-string">"btn-size--small"</span>,
      medium: <span class="hljs-string">"btn-size--medium"</span>
    }
  },
  defaultVariants: {
    intent: <span class="hljs-string">"primary"</span>,
    size: <span class="hljs-string">"medium"</span>
  }
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> ButtonVariantProps = GetVariantProps&lt;<span class="hljs-keyword">typeof</span> button&gt;;

<span class="hljs-keyword">type</span> ButtonOwnProps = {
  <span class="hljs-comment">// ... some button props ...</span>
};

<span class="hljs-keyword">type</span> ButtonProps = React.PropsWithChildren&lt;ButtonVariantProps &amp; ButtonOwnProps&gt;;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Button</span>(<span class="hljs-params">props: ButtonProps</span>) </span>{
  <span class="hljs-keyword">const</span> { intent, size, children, ...rest } = props;

  <span class="hljs-comment">// applied classes list</span>
  <span class="hljs-keyword">const</span> variants = button({ intent, size });
  <span class="hljs-keyword">const</span> classes = clsx(variants);

  <span class="hljs-keyword">return</span> (
    &lt;button className={classes} {...rest}&gt;
      {children}
    &lt;/button&gt;
  );
}
</code></pre>
<p>As you saw the library took care of all style mapping and generated applicable classes for you.</p>
<p>Facts from <a target="_blank" href="https://variant-styles.vercel.app/">@vtechguys/vs documentation</a>:</p>
<ul>
<li><p><strong>🫶 Framework agnostic</strong></p>
</li>
<li><p><strong>🔥 Typesafe</strong></p>
</li>
<li><p><strong>🤏 Super tiny bundle size</strong></p>
</li>
</ul>
<p>Let's simplify things by using this tiny package and create awesome variant components for your design system.</p>
<ul>
<li><p><a target="_blank" href="https://www.npmjs.com/package/@vtechguys/vs">NPM Link</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/vtechguys/vs">Github Link</a></p>
</li>
<li><p><a target="_blank" href="https://variant-styles.vercel.app/">Documentation Website</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Creating database and tables | PostgreSQL]]></title><description><![CDATA[You create a database to store all your data and information in one place. The database is like an envelope containing and enclosing many sheets of data called tables.   

The sheets represent the tables in the database where your data is stored. Dat...]]></description><link>https://aniketjha.dev/creating-database-and-tables-postgresql-c1l1</link><guid isPermaLink="true">https://aniketjha.dev/creating-database-and-tables-postgresql-c1l1</guid><category><![CDATA[PostgreSQL]]></category><category><![CDATA[Databases]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[backend]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Aniket Jha]]></dc:creator><pubDate>Sat, 08 Oct 2022 07:17:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1665213440724/d0QZrguYs.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You create a database to store all your data and information in one place. The database is like an envelope containing and enclosing many sheets of data called tables.   </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664168908706/fNYSdSNTw.png" alt="Database_Table_analogy.png" class="image--center mx-auto" /></p>
<p>The sheets represent the tables in the database where your data is stored. Data is stored in a grid or tabular format as shown below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665213951294/GyWJIc7FM.png" alt="sheet_table.png" class="image--center mx-auto" /></p>
<p>Each row in the grid is an entry in the table.</p>
<h3 id="heading-creating-database">Creating database</h3>
<pre><code class="lang-SQL"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">DATABASE</span> store_database;
</code></pre>
<p>The above command creates a database called <code>store_database</code> for us it is the name of the envelope where we will put our <em>store</em> sheets.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665206895399/19Jj6U5s0.png" alt="store_database_envelope_analogy.png" class="image--center mx-auto" /></p>
<h3 id="heading-creating-tables">Creating Tables</h3>
<p>What is data a store manager would like to keep?</p>
<ul>
<li>Employee details</li>
<li>Product details</li>
<li>Order details</li>
</ul>
<p>These are called entities, each entity served a specific purpose, you cannot put employee details and product details together. For us, they mean a sheet in an envelope, each sheet in the envelope has particular data written on it. A sheet may be a list of products in the store, another sheet may be a list of employees in the store. In the terms of the SQL, each of these sheets represents a table in the database.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665208429120/HZTtTC3Os.png" alt="sheets.png" class="image--center mx-auto" /></p>
<p>Each of the sheets (table) stores only one kind of data object(entity). Each entity has some attribute associated with it, for example, an employee Aniket has an ID, Name, and Salary whereas a product has an ID, Name, and Price. These attributes or columns are properties of the entity and will vary as the entity varies.</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> employees (
  <span class="hljs-keyword">id</span> bigserial,
  full_name <span class="hljs-built_in">varchar</span>(<span class="hljs-number">50</span>),
  salary <span class="hljs-built_in">numeric</span>
);
</code></pre>
<p>The above commands create a sheet/table for Employee data with each employee having properties <strong>id</strong>, <strong>full_name</strong>, and <strong>salary.</strong></p>
<p>If you look at the above command you will notice <code>full_name varchar(50)</code> the <strong>full_name</strong>  is the field or attribute an employee has whereas <code>varchar(50)</code> is the datatype the column/attribute can have, i.e name can only be characters in the same way <strong>salary</strong> can only be <code>numeric</code> and not a char because <code>2500qwerty</code> is not a valid salary but <code>2500</code> is a valid salary.</p>
<h3 id="heading-inserting-rows-into-table">Inserting rows into table</h3>
<p>Let's start putting the data of employees in the employee table.</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> store_database
  (full_name,    salary)
<span class="hljs-keyword">VALUES</span>
  (<span class="hljs-string">'Aniket'</span>,     <span class="hljs-number">2500</span>),
  (<span class="hljs-string">'Robert'</span>,    <span class="hljs-number">2600</span>);
</code></pre>
<ul>
<li>The above command <strong>insert</strong> data into <strong>store_database</strong>. </li>
<li>If you notice we are specifying the attribute or <strong>column names</strong> for which data has to be inserted. </li>
<li>Notice we are inserting multiple values <code>(...), (...)</code> as comma-separated in parathesis. </li>
<li>Data will appear in order of insertion</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665212202842/98P8WETwC.gif" alt="animation.gif" class="image--center mx-auto" /></p>
<p>The result looks like the following in the PostgresSQL</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665212627287/e8uFRQPHF.png" alt="Screenshot 2022-10-08 at 12.32.27 PM.png" class="image--center mx-auto" /></p>
<p>In this article, we have learned how to create a database and table, and how to insert data into those tables. In the next article, we will learn how to read and query this tables.</p>
]]></content:encoded></item><item><title><![CDATA[Extending our CSS-in-JS to support style-component syntax]]></title><description><![CDATA[In the previous post, we made our css emotion like function and in this blog post, we are going to extend our css function to support the following style-components syntax.
const Button = styled('button')(
  {
    backgroundColor:  "blue",
    color:...]]></description><link>https://aniketjha.dev/extending-our-css-in-js-to-support-style-component-syntax</link><guid isPermaLink="true">https://aniketjha.dev/extending-our-css-in-js-to-support-style-component-syntax</guid><category><![CDATA[CSS]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[CSS in JS]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[React]]></category><dc:creator><![CDATA[Aniket Jha]]></dc:creator><pubDate>Wed, 24 Aug 2022 05:26:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1661324980750/fGbtrigRD.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the <a target="_blank" href="https://aniketjha.dev/build-your-own-emotion-like-css-in-js-library">previous post</a>, we made our <code>css</code> emotion like function and in this blog post, we are going to extend our <code>css</code> function to support the following style-components syntax.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Button = styled(<span class="hljs-string">'button'</span>)(
  {
    <span class="hljs-attr">backgroundColor</span>:  <span class="hljs-string">"blue"</span>,
    <span class="hljs-attr">color</span>: <span class="hljs-string">"white"</span>
  }
)
</code></pre>
<p>A few things to note when exploring the API are: ```jsx // On breaking into parts: const Button = // &lt;-- Part: 3 styled('button') // &lt;-- Part: 1 ({ backgroundColor: 'blue' }) // &lt;-- Part: 2</p>
<pre><code class="lang-plaintext">- Part 1: The `styled` function takes the `tagName` that has to be created i.e

```jsx
 styled('button') &lt;-- 1

// is equivalent to

&lt;button&gt;
</code></pre>
<ul>
<li>Part 2: The <code>styled(tagName)</code> returns a function that accepts <code>style-object</code> which will be used to style this <code>tagName</code> element.</li>
</ul>
<pre><code class="lang-jsx">({ <span class="hljs-attr">backgroundColor</span>: <span class="hljs-string">"blue"</span> }) &lt;-- Part <span class="hljs-number">2</span>

<span class="hljs-comment">// is converted to </span>

css({ <span class="hljs-attr">backgroundColor</span>: <span class="hljs-string">"blue"</span> }) 

<span class="hljs-comment">// and passed to the component as</span>

&lt;button className={css(...)} /&gt;
</code></pre>
<ul>
<li>The complete call returns a React component <code>Button</code> that renders a <code>button</code> with a given style.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661315488639/_062dWi86.png" alt="Rendering a button using style-component like syntax" class="image--center mx-auto" /></p>
<p>From the above points, we can write a rough husk of our <code>styled</code> function</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// Part 1: styled('button'): element of type tagName to render</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">styled</span>(<span class="hljs-params">tagName</span>) </span>{ 
  <span class="hljs-comment">// Part 2: style('button')({ color: 'white' }) takes in the style object and applies these styles to `tagName=button` component</span>

  <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">applyStyles</span>(<span class="hljs-params">styleObject</span>) </span>{ 
      <span class="hljs-comment">// Part 3: `Button` react component </span>
      <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Component</span>(<span class="hljs-params">props</span>) </span>{ 
          <span class="hljs-comment">// ...styling and element creation... </span>
          <span class="hljs-comment">// Mark: 1</span>
      }
  }
}
</code></pre>
<p>Now in place <strong>Mark: 1</strong> we need to do the following:</p>
<ul>
<li><p>Create an element using <code>React.createElement</code> of type <code>tagName</code></p>
</li>
<li><p>Pass <code>style-object</code> into <code>css</code> function to generate name, as props may already contain some className so compose these className together.</p>
</li>
</ul>
<pre><code class="lang-jsx"><span class="hljs-comment">// continue from Mark: 1</span>

<span class="hljs-keyword">const</span> clonedProps = clone(props);
<span class="hljs-comment">// a copy of props is required as by default react makes props immutable</span>
<span class="hljs-comment">// and if we want to modify any props we need to make a copy for our use</span>

<span class="hljs-comment">// compute a className for styleObject</span>
<span class="hljs-keyword">const</span> generatedClassName = css(styleObject);

<span class="hljs-comment">// compose className </span>
<span class="hljs-keyword">const</span> className = generatedClassName + props.className ? + <span class="hljs-string">` <span class="hljs-subst">${props.className}</span>`</span> : <span class="hljs-string">''</span>;

<span class="hljs-comment">// reassign composed className</span>
clonedProps.className = className;

<span class="hljs-comment">// create element of type `tagName` with props = `clonedProps` and `style=generateClassName`</span>
<span class="hljs-keyword">const</span> element = React.createElement(tagName, clonedProps);

<span class="hljs-comment">// The `element` is of type `tagName` and of `styles=styleObject` this is one we want to render</span>

<span class="hljs-keyword">return</span> element;
</code></pre>
<p>That is what the <code>style-components</code> version of our CSS-in-JS library looks like. <code>clone</code> function can be as simple as:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> clone = <span class="hljs-function">(<span class="hljs-params">obj</span>) =&gt;</span> <span class="hljs-built_in">Object</span>.assign({}, obj);
</code></pre>
<p>More reads on the CSS-in-JS:</p>
<ul>
<li><p><a target="_blank" href="https://aniketjha.dev/why-css-in-js">Why CSS-in-JS?</a></p>
</li>
<li><p><a target="_blank" href="https://aniketjha.dev/css-isolation-vs-abstraction">CSS: Isolation vs Abstraction</a></p>
</li>
<li><p><a target="_blank" href="https://aniketjha.dev/build-your-own-emotion-like-css-in-js-library">Build your own emotion like CSS-in-JS library</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/vtechguys/styler">Styler GitHub</a></p>
</li>
<li><p><a target="_blank" href="https://codesandbox.io/s/styler-sd2xbl">Styler Codesandbox</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Build your own emotion like CSS-in-JS library]]></title><description><![CDATA[In this blog post, we will try to understand CSS-in-JS by creating our own version of emotion.js. Emotion is one of the most popular CSS-in-JS solutions out there. 
There are some brilliant minds working on emotion, we aren't going to recreate emotio...]]></description><link>https://aniketjha.dev/build-your-own-emotion-like-css-in-js-library</link><guid isPermaLink="true">https://aniketjha.dev/build-your-own-emotion-like-css-in-js-library</guid><category><![CDATA[CSS]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[CSS in JS]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[React]]></category><dc:creator><![CDATA[Aniket Jha]]></dc:creator><pubDate>Sun, 14 Aug 2022 20:27:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1660505640778/Isv_j5hbU.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this blog post, we will try to understand CSS-in-JS by creating our own version of <a target="_blank" href="https://emotion.sh/docs/introduction">emotion.js</a>. Emotion is one of the most popular CSS-in-JS solutions out there. </p>
<p>There are some brilliant minds working on emotion, we aren't going to recreate emotion with all its complexities and optimization just that we are trying to develop a better understanding of such CSS-in-JS libraries by building one on our own.</p>
<p>Let us start by exploring API and see what emotion does for us.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660458938471/lOCJ800Er.png" alt="Screenshot 2022-08-14 at 12.05.10 PM.png" class="image--center mx-auto" /></p>
<p>So the emotion package exports a function called <code>css</code> which takes <code>style-object</code> as an argument and returns a unique <code>className</code> which is used by our<code>div</code> to apply some style. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660459589995/pxwizL4AD.png" alt="Screenshot 2022-08-14 at 12.11.31 PM.png" class="image--center mx-auto" /></p>
<p>Another overload signature <code>css</code> function can also take an array of <code>style-object</code> as an argument. For example: </p>
<pre><code class="lang-jsx">css(
  [  <span class="hljs-comment">// &lt;-- array of </span>
    { <span class="hljs-attr">padding</span>: <span class="hljs-string">'32px'</span>, <span class="hljs-attr">backgrounColor</span>: <span class="hljs-string">'orange'</span> }, <span class="hljs-comment">// &lt;-- style object 1</span>
    { <span class="hljs-attr">fontSize</span>: <span class="hljs-string">'24px'</span>, <span class="hljs-attr">borderRadius</span>: <span class="hljs-string">'4px'</span> } <span class="hljs-comment">// &lt;-- style object 2</span>
  ]
)
</code></pre>
<p>In the DOM <code>css</code> function injects a <code>&lt;style&gt;</code> in the <code>document.head</code> where it keeps the compiled CSS created from calling <code>css</code> function on the <code>style-object</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660459576090/ycjG8M-eB.png" alt="Screenshot 2022-08-14 at 12.11.18 PM.png" class="image--center mx-auto" /></p>
<p>Summarising emotion <code>css</code> function:</p>
<ul>
<li><code>css</code> function takes an object or array of objects as an argument.</li>
<li>These objects are called <code>style-object</code> which is a way of writing CSS with JavaScript objects.</li>
<li>It returns a unique <code>className</code> for the given <code>style-object</code>.</li>
<li>It compiles the <code>style-object</code> into valid <code>CSS</code> and injects a <code>style</code> tag containing our compiled <code>CSS</code> into the <code>document.head</code></li>
</ul>
<h2 id="heading-the-css-function">The <code>css</code> Function</h2>
<p>Let's break it down is a series of programmatic steps:</p>
<ol>
<li>Convert to a valid <code>style-object</code>.</li>
<li>Generate a unique className for the <code>style-object</code>.</li>
<li>Parse the <code>style-object</code> to generate valid CSS styles and attach them to className.</li>
<li>Inject the parsed CSS into a stylesheet in DOM.</li>
</ol>
<p>Following our programmatic steps our <code>css</code> function should look like:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">css</span>(<span class="hljs-params">styles</span>) </span>{

  <span class="hljs-comment">// 1. convert to valid style-object</span>
  <span class="hljs-keyword">const</span> _style_object_ = getValidStyleObject(styles);

  <span class="hljs-comment">// 2. generate unique className</span>
  <span class="hljs-keyword">const</span> className = getClassName(_style_object_);

  <span class="hljs-comment">// 3. Parse the style-object to generate valid CSS styles and attach them to className</span>
  <span class="hljs-keyword">const</span> CSS = parseStyles(_styles_object_, className);

  <span class="hljs-comment">// 4. Create or update the stylesheet in DOM</span>
  injectStyles(CSS);

  <span class="hljs-comment">// return className to be applied on element</span>
  <span class="hljs-keyword">return</span> className;
}
</code></pre>
<h3 id="heading-step-1-convert-to-a-valid-style-object">Step 1: Convert to a valid  <code>style-object</code></h3>
<p>The <code>css</code> function can accept a <code>style-object</code> or an array of <code>style-object</code>. In the case of the array of <code>style-object</code> we must merge those to generate a single style object.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getValidStyleObject</span>(<span class="hljs-params">styles</span>) </span>{
  <span class="hljs-keyword">let</span> style_object = styles;

  <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Array</span>.isArray(styles)) {
    style_object = merge(styles);
  }

  <span class="hljs-keyword">return</span> style_object;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">merge</span>(<span class="hljs-params">styles</span>) </span>{
  <span class="hljs-comment">// (*) shallow merge</span>
  <span class="hljs-keyword">return</span> styles.reduce(<span class="hljs-function">(<span class="hljs-params">acc, style</span>) =&gt;</span> <span class="hljs-built_in">Object</span>.assign(acc, style), {}); 
}
</code></pre>
<p>It should be noted that this is a shallow merge which will simply replace the properties of the former one with a later one, for the nested properties simple replacement may cause an issue so we out for <a target="_blank" href="https://thewebdev.info/2021/03/06/how-to-deep-merge-javascript-objects/">deep-merge</a> if required</p>
<h3 id="heading-step-2-generate-a-unique-classname-for-the-style-object">Step 2: Generate a unique className for the <code>style-object</code></h3>
<p>After step 1 we have received a valid <code>style-object</code> and now we can process this object to generate unique className for it.</p>
<ul>
<li>Generating a unique className is required makes sure that there are no naming conflicts anywhere in the application; </li>
<li>Unique className eliminates the need for any naming conventions like <a target="_blank" href="https://css-tricks.com/bem-101/">BEM</a>, which makes the life of the dev easier. </li>
<li>For generating names we should make sure that we always come up with the same name for the same 
structured style object.</li>
</ul>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> styleObject1 = {
  <span class="hljs-attr">fontSize</span>: <span class="hljs-string">'16px'</span>,
  <span class="hljs-attr">fontWeight</span>: <span class="hljs-number">600</span>
};

<span class="hljs-keyword">const</span> styleObject2 = {
  <span class="hljs-attr">fontSize</span>: <span class="hljs-string">'16px'</span>,
  <span class="hljs-attr">fontWeight</span>: <span class="hljs-number">600</span>
};

styleObject1 === styleObject2; <span class="hljs-comment">// false: reference is different</span>
getClassName(styleObject) === getClassName(styleObject2); <span class="hljs-comment">// true: Pure and Idempotent nature</span>
</code></pre>
<ul>
<li>For maintaining Pure and Idempotent nature of <code>getClassName</code> function we will hash <code>style-object</code> so that it always returns the same output className for the same <em>structured</em> <code>style-object</code>. The hashing function needs input to be a string so we need to convert our <code>style-object</code> into a string. I will simply use <code>JSON.stringify</code> for our case. But there is a catch see below.</li>
</ul>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> obj1 = { <span class="hljs-attr">a</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">b</span>: <span class="hljs-number">2</span> };
<span class="hljs-keyword">const</span> obj2 = { <span class="hljs-attr">b</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">a</span>: <span class="hljs-number">1</span> };

obj1 == obj2; <span class="hljs-comment">// false: diff references</span>

<span class="hljs-comment">// an ideal stringifying function</span>
stringify(obj1) === stringify(obj2) <span class="hljs-comment">// true: '{ "a": 1, "b": 2 }'</span>

<span class="hljs-comment">// our JSON.stringify </span>
<span class="hljs-built_in">JSON</span>.strinfigy(obj1) === <span class="hljs-built_in">JSON</span>.stringify(obj2) <span class="hljs-comment">// false</span>
<span class="hljs-comment">// '{ "a": 1, "b": 2 }' === '{ "b": 2, "a": 1 }' // false</span>
</code></pre>
<ul>
<li><code>JSON.stringify</code> is not an ideal stringifying utility as for same looking object it gives different string output. So If we plan to use <code>JSON.stringify</code> our hashes will also vary.</li>
</ul>
<pre><code class="lang-js"><span class="hljs-comment">// it is a cache map of "serialized-style-object" to "hashed-style-object"</span>
<span class="hljs-keyword">const</span> style_classname_cache = {};

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getClassName</span>(<span class="hljs-params">styleObject</span>) </span>{
  <span class="hljs-keyword">const</span> stringified = stringify(styleObject);

  <span class="hljs-comment">// pick the cached className to optimize and skip hashing every time</span>
  <span class="hljs-keyword">let</span> className = style_classname_cache[stringified];

  <span class="hljs-comment">// if there is not an entry for this stringified style means it is new</span>
  <span class="hljs-comment">// so generate a hashed className and register and entry of style</span>

  <span class="hljs-keyword">if</span> (!className) {

    <span class="hljs-comment">// use any quick hashing algorithm</span>
    <span class="hljs-comment">// example: https://gist.github.com/jlevy/c246006675becc446360a798e2b2d781</span>

    <span class="hljs-keyword">const</span> hashed = hash(stringified);
    <span class="hljs-comment">// prefix some string to indicate it is generated from lib</span>
    <span class="hljs-comment">// it also makes sure that className is valid</span>
    <span class="hljs-keyword">const</span> _class_name_ = <span class="hljs-string">`css-<span class="hljs-subst">${hashed}</span>`</span>;

    <span class="hljs-comment">// hashing is costly so make an entry for the generated className</span>
    style_classname_cache[stringified] = _class_name_;

    className = style_classname_cache[stringified];
  }

  <span class="hljs-keyword">return</span> className;
}
</code></pre>
<p>Now let's proceed to next step where we will parse the <code>style-object</code> to generate CSS string.</p>
<pre><code class="lang-js"><span class="hljs-comment">// it is a map of "stringified-style-object" to "hashed-classname"</span>
<span class="hljs-keyword">const</span> style_classname_cache = {};

<span class="hljs-comment">// inside css function</span>
<span class="hljs-comment">// ...</span>
<span class="hljs-keyword">const</span> className = getClassName(....);

<span class="hljs-keyword">let</span> CSS = classname_css_cache[className];

<span class="hljs-keyword">if</span> (!CSS) {
  CSS = parseStyles(_style_object_, className); <span class="hljs-comment">// &lt;-- Step 3</span>
  classname_css_cache[classname] = CSS;
}
</code></pre>
<h3 id="heading-step-3-parse-the-style-object-to-generate-valid-css-styles-and-attach-them-to-classname">Step 3: Parse the <code>style-object</code> to generate valid CSS styles and attach them to className</h3>
<p>This is the toughest part where we process the <code>style-object</code> and generate valid CSS rule declations from them. Before we proceed let's take an example:</p>
<pre><code class="lang-js">  <span class="hljs-comment">// style-object</span>
  <span class="hljs-keyword">const</span> styles = { 
    <span class="hljs-attr">width</span>: <span class="hljs-string">'600px'</span>,
    <span class="hljs-attr">fontSize</span>: <span class="hljs-string">'16px'</span>, <span class="hljs-comment">// style-rule 1</span>
    <span class="hljs-attr">fontWeight</span>: <span class="hljs-number">600</span>, <span class="hljs-comment">// style-rule 2,</span>
    <span class="hljs-attr">color</span>: <span class="hljs-string">'red'</span>,
    <span class="hljs-string">'&amp;:hover, &amp;:active'</span>: {
        <span class="hljs-attr">color</span>: <span class="hljs-string">'green'</span>,
    },
    <span class="hljs-string">'&amp;[data-type="checkbox"]'</span>: {
      <span class="hljs-attr">border</span>: <span class="hljs-string">'1px solid black'</span>
    },
    <span class="hljs-string">'@media(max-width: 1200px)'</span>: {
       <span class="hljs-attr">width</span>: <span class="hljs-string">'200px'</span>
    }
   };

  css(styles)

  <span class="hljs-comment">// compiled CSS from `style-object`</span>
  .css<span class="hljs-number">-123</span> { 
    font-size: <span class="hljs-number">16</span>px;
    font-weight: <span class="hljs-number">600</span>px;
  }

  <span class="hljs-comment">// ! NOTE !</span>

  <span class="hljs-comment">// 1) .css-123 is selector name or class-name here</span>
  <span class="hljs-comment">// 2) { and } marks style blocks/bound for this selector, each </span>
  <span class="hljs-comment">//      block need to be parsed</span>
  <span class="hljs-comment">// 3) font-size: 16px is processed CSS for`fontSize: '16px'`</span>
  <span class="hljs-comment">// 4) `&amp;:hover, &amp;:active' are two blocks ideally joined by a `,`</span>
  <span class="hljs-comment">//      i.e '&amp;:hover' and '&amp;:active'</span>
  <span class="hljs-comment">// 5)  '&amp;:hover' block is read as `css-123:hover` where</span>
  <span class="hljs-comment">//      `&amp;` is replaced by current selector name</span>
  <span class="hljs-comment">// 6) `&amp;[data-type="checkbox"]` attributes based styling is also possible</span>
  <span class="hljs-comment">// 7) @ rules are specific rule ex: @media screen size rules </span>
  <span class="hljs-comment">//      so it should be processed early</span>
  <span class="hljs-comment">// 8) each nested style (ex: &amp;:hover) need to be parsed </span>
  <span class="hljs-comment">//      i.e recursive calling</span>
</code></pre>
<p>From the above-gathered notes, we can write our <code>parseStyles</code> as</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseStyles</span>(<span class="hljs-params">style_object, selector</span>) </span>{
  <span class="hljs-comment">// This collects `@import` rules  which are independent of any selector</span>
  <span class="hljs-keyword">let</span> outer = <span class="hljs-string">""</span>;

  <span class="hljs-comment">// This is for block rules collected</span>
  <span class="hljs-keyword">let</span> blocks = <span class="hljs-string">""</span>;
  <span class="hljs-number">2</span>;

  <span class="hljs-comment">// This is for the currently processed style-rule</span>
  <span class="hljs-keyword">let</span> current = <span class="hljs-string">""</span>;

  <span class="hljs-comment">// each property of style_object can be a rule (3)</span>
  <span class="hljs-comment">// or a nested styling 7, 8</span>
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> key <span class="hljs-keyword">in</span> style_object) {
    <span class="hljs-keyword">const</span> value = style_object[key];

    <span class="hljs-comment">// @ rules are specific and may be further nested</span>
    <span class="hljs-comment">// @media rules are essentially redefining styles on-screen breakpoints</span>
    <span class="hljs-comment">// so they need to be processed first</span>
    <span class="hljs-keyword">const</span> isAtRule = key[<span class="hljs-number">0</span>] === <span class="hljs-string">"@"</span>;

    <span class="hljs-keyword">if</span> (isAtRule) {
      <span class="hljs-comment">// There are 4 main at-rules</span>
      <span class="hljs-comment">// 1. @import</span>
      <span class="hljs-comment">// 2. @font-face</span>
      <span class="hljs-comment">// 3. @keyframe</span>
      <span class="hljs-comment">// 4. @media</span>

      <span class="hljs-keyword">const</span> isImportRule = key[<span class="hljs-number">1</span>] === <span class="hljs-string">"i"</span>;
      <span class="hljs-keyword">const</span> isFontFaceRule = key[<span class="hljs-number">1</span>] === <span class="hljs-string">"f"</span>;
      <span class="hljs-keyword">const</span> isKeyframeRule = key[<span class="hljs-number">1</span>] === <span class="hljs-string">"k"</span>;

      <span class="hljs-keyword">if</span> (isImportRule) {
        <span class="hljs-comment">// import is an outer rule declaration</span>
        outer += key + <span class="hljs-string">" "</span> + value; <span class="hljs-comment">// @import nav.css</span>
      } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (isFontFaceRule) {
        <span class="hljs-comment">// font face rules are global block rules but don't need a bound selector</span>
        blocks += parseStyles(value, key);
      } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (isKeyframeRule) {
        <span class="hljs-comment">// keyframe rule are processed differently by our `css` function</span>
        <span class="hljs-comment">// which we should see implementation at a later point</span>
        blocks += key + <span class="hljs-string">"{"</span> + parseStyles(value, <span class="hljs-string">""</span>) + <span class="hljs-string">"}"</span>;
      } <span class="hljs-keyword">else</span> {
        <span class="hljs-comment">// @media rules are essentially redefining CSS on breakpoints</span>
        <span class="hljs-comment">// they are nested rules and are bound to selector</span>
        blocks += key + <span class="hljs-string">"{"</span> + parseStyles(value, selector) + <span class="hljs-string">"}"</span>;
      }
    }
    <span class="hljs-comment">// beside the At-Rules there are other nested rules</span>
    <span class="hljs-comment">// 4, 5, 6</span>
    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> value === <span class="hljs-string">"object"</span>) {
      <span class="hljs-comment">// the nested rule can be simple as "&amp;:hover"</span>
      <span class="hljs-comment">// or a group of selectors like "&amp;:hover, &amp;:active" or</span>
      <span class="hljs-comment">// "&amp;:hover .wrapper"</span>
      <span class="hljs-comment">// "&amp;:hover [data-toggled]"</span>
      <span class="hljs-comment">// many such complex selector we will have to break them into simple selectors</span>
      <span class="hljs-comment">// "&amp;:active, &amp;:hover" should be simplified to "&amp;:hover" and "&amp;:active"</span>
      <span class="hljs-comment">// finally removing self-references (&amp;) with class-name(root-binding `selector`)</span>
      <span class="hljs-keyword">const</span> selectors = selector
        ? <span class="hljs-comment">// replace multiple selectors</span>
          selector.replace(<span class="hljs-regexp">/([^,])+/g</span>, <span class="hljs-function">(<span class="hljs-params">_seletr</span>) =&gt;</span> {
            <span class="hljs-comment">// check the key for '&amp;:hover' like</span>

            <span class="hljs-keyword">return</span> key.replace(<span class="hljs-regexp">/(^:.*)|([^,])+/g</span>, <span class="hljs-function">(<span class="hljs-params">v</span>) =&gt;</span> {
              <span class="hljs-comment">// replace self-references '&amp;' with '_seletr'</span>

              <span class="hljs-keyword">if</span> (<span class="hljs-regexp">/&amp;/</span>.test(v)) <span class="hljs-keyword">return</span> v.replace(<span class="hljs-regexp">/&amp;/g</span>, _seletr);

              <span class="hljs-keyword">return</span> _seletr ? _seletr + <span class="hljs-string">" "</span> + v : v;
            });
          })
        : key;
      <span class="hljs-comment">// each of these nested selectors create their own blocks</span>
      <span class="hljs-comment">// &amp;:hover {} has its own block</span>
      blocks += parseStyles(value, selectors);
    }
    <span class="hljs-comment">// now that we have dealt with object `value`</span>
    <span class="hljs-comment">// it means we are a simple style-rules (3)</span>
    <span class="hljs-comment">// style-rule values should not be undefined or null</span>
    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (value !== <span class="hljs-literal">undefined</span>) {
      <span class="hljs-comment">// in JavaScript object keys are camelCased by default</span>
      <span class="hljs-comment">// i.e "textAlign" but it is not a valid CSS property</span>
      <span class="hljs-comment">// so we should convert it to valid CSS-property i.e "text-align"</span>

      <span class="hljs-comment">// Note: the key can be a CSS variable that starts from "--"</span>
      <span class="hljs-comment">// which need to remain as it is as they will be referred by value in code somewhere.</span>
      <span class="hljs-keyword">const</span> isVariable = key.startsWith(<span class="hljs-string">"--"</span>)

      <span class="hljs-comment">// prop value as per CSS "text-align" not "textAlign"</span>
      <span class="hljs-keyword">const</span> cssProp = isVariable
        ? key
        : key.replace(<span class="hljs-regexp">/[A-Z]/g</span>, <span class="hljs-string">"-$&amp;"</span>).toLowerCase();

      <span class="hljs-comment">// css prop is written as "&lt;prop&gt;:&lt;value&gt;;"</span>
      current += cssProp + <span class="hljs-string">":"</span> + value + <span class="hljs-string">";"</span>;
    }
  }

  <span class="hljs-keyword">return</span> (
    <span class="hljs-comment">// outer are independent rules</span>
    <span class="hljs-comment">// and it is most likely to be the @import rule so it goes first</span>
    outer +
    <span class="hljs-comment">// if there are any current rules (style-rule)(3)</span>
    <span class="hljs-comment">// attach them to selector-block if any else attach them there</span>
    (selector &amp;&amp; current ? selector + <span class="hljs-string">"{"</span> + current + <span class="hljs-string">"}"</span> : current) +
    <span class="hljs-comment">// all block-level CSS goes next</span>
    blocks
  );
}
</code></pre>
<p>At this point, we have compiled CSS from <code>style_object</code> and all that is left is to inject it into the DOM.</p>
<h3 id="heading-step-4-inject-the-parsed-css-into-a-stylesheet-in-dom">Step 4: Inject the parsed CSS into a stylesheet in DOM</h3>
<p>For this step, we will create a <code>&lt;style&gt;</code> tag using <code>document.createElement</code> and inside of that style tag, we will append our styles in the<code>textNode</code>.</p>
<ul>
<li>Create a <code>&lt;style id="css-in-js"&gt;</code> element if doesn't already exist;</li>
<li>Get the text-node i.e <code>stylesheet.firstChild</code> and append CSS string from <code>parseStyles</code> in it.</li>
</ul>
<pre><code class="lang-js"><span class="hljs-comment">// in case the process isn't running in a browser instance </span>
<span class="hljs-comment">// so we fake stylesheet-text-node behavior </span>
<span class="hljs-keyword">const</span> fake_sheet = {
  <span class="hljs-attr">data</span>: <span class="hljs-string">''</span>
};

<span class="hljs-comment">// keep track of all styles inserted so that we don't insert the same styles again</span>
<span class="hljs-keyword">const</span> inserted_styles_cache = {};

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">injectStyles</span>(<span class="hljs-params">css_string</span>) </span>{
  <span class="hljs-comment">// create and get the style-tag; return the text node directly</span>
  <span class="hljs-keyword">const</span> stylesheet = getStyleSheet();

  <span class="hljs-comment">// if already inserted style in the sheet we might ignore this call</span>
  <span class="hljs-keyword">const</span> hasInsertedInSheet = inserted_styles_cache[css_string];
  <span class="hljs-comment">// these styles need to be inserted</span>
  <span class="hljs-keyword">if</span> (!hasInsertedInSheet) {
    stylesheet.data += css_string; <span class="hljs-comment">// &lt;-- inserted style in sheet</span>
    inserted_styles_cache[css_string] = <span class="hljs-literal">true</span>; <span class="hljs-comment">// &lt;-- mark the insertion</span>
  }
}

<span class="hljs-function"><span class="hljs-keyword">function</span>  <span class="hljs-title">getStyleSheet</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// we aren't in the browser env so our fake_sheet will work</span>
  <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> <span class="hljs-built_in">window</span> === <span class="hljs-string">"undefined"</span>) {
      <span class="hljs-keyword">return</span> fake_sheet;
  }

  <span class="hljs-keyword">const</span> style = <span class="hljs-built_in">document</span>.head.querySelector(<span class="hljs-string">'#css-in-js'</span>);

  <span class="hljs-keyword">if</span> (style) {
    <span class="hljs-keyword">return</span> style.firstChild; <span class="hljs-comment">// &lt;-- text-node containing styles</span>
  }

  <span class="hljs-comment">// style doesn't already exist create a style-element</span>
  <span class="hljs-keyword">const</span> styleTag = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'style'</span>);

  styleTag.setAttribute(<span class="hljs-string">'id'</span>, <span class="hljs-string">'css-in-js'</span>);
  styleTag.innerHTML = <span class="hljs-string">' '</span>;

  <span class="hljs-built_in">document</span>.head.appendChild(styleTag);

  <span class="hljs-keyword">return</span> styleTag.firstChild; <span class="hljs-comment">// &lt;-- text-node containing styles</span>
}
</code></pre>
<p>🎉<strong><em> Congratulations with that in place we have created our own CSS-in-JS library.</em></strong> 🎉</p>
<p>As for the <code>keyframes</code>, we can use our <code>css</code> function but with little modifications. 
Let's see the API and how its use first.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> growAnimationName = keyframes({ <span class="hljs-comment">// &lt;-- argument is called keyframe-style-object</span>
  <span class="hljs-attr">from</span>: { <span class="hljs-attr">transform</span>: <span class="hljs-string">'scale(1)'</span> }, 
  <span class="hljs-attr">to</span>: { <span class="hljs-attr">transform</span>: <span class="hljs-string">'scale(2)'</span> },
}); <span class="hljs-comment">// &lt;-- call to keyframe with style-object returns animation-name. eg: (css-987)</span>

<span class="hljs-comment">// used as</span>
css({  <span class="hljs-attr">width</span>: <span class="hljs-string">'100px'</span>, <span class="hljs-attr">height</span>: <span class="hljs-string">'100px'</span>,  <span class="hljs-attr">animation</span>: <span class="hljs-string">`<span class="hljs-subst">${growAnimationName}</span> 2s ease infinite`</span> });

<span class="hljs-comment">// compiled as</span>
<span class="hljs-comment">//  @keyframe css-987 {  </span>
<span class="hljs-comment">//     from: { transform: scale(1) };</span>
<span class="hljs-comment">//     to: { transform: scale(2) };</span>
<span class="hljs-comment">//  }</span>
</code></pre>
<ul>
<li>Keyframes have a similar API where it takes a <code>keyframe-style-object</code>.</li>
<li>Keyframes return to the animation name; they are not bound to a class/selector scope.</li>
<li>The <code>css</code> function only needs an animation name to apply styling which means keyframes need not be in <code>css</code> function style object definition.</li>
<li>Keyframes are global where <code>keyframe-style-object</code> is stringified and hashed to generate animation name same as in the case generating className from any <code>style-object</code>. </li>
<li>These names are the only scope of keyframes it is global.</li>
<li>If you note carefully we never write the <code>@keyframes</code> keyword in the <code>keyframes</code> function call so that is something added internally along with the animation-name.</li>
<li>This conversion from a <code>keyframe-style-object</code> to <code>style-object</code> can look something like:</li>
</ul>
<pre><code class="lang-js"><span class="hljs-comment">// keyframe-style-object</span>
{   
  <span class="hljs-attr">from</span>: { <span class="hljs-attr">transform</span>: <span class="hljs-string">'scale(1)'</span> }, 
  <span class="hljs-attr">to</span>: { <span class="hljs-attr">transform</span>: <span class="hljs-string">'scale(2)'</span> }
}

<span class="hljs-comment">// converted style-object</span>
{
  [<span class="hljs-string">`@keyframes <span class="hljs-subst">${animationName}</span>`</span>]: keyframe-style-object 
}
</code></pre>
<p>Adding keyframes support to <code>css</code> function can be done simply by telling <code>css</code> function to treat this <code>css</code> call as a <code>keyframe</code> function call and do the above conversion before parsing the <code>style-object</code>.</p>
<pre><code class="lang-js"><span class="hljs-comment">// adding one more parameter called `options` </span>
<span class="hljs-comment">// this can be used to change the behavior of `css` function and</span>
<span class="hljs-comment">// it should be an optional parameter.</span>
<span class="hljs-comment">// changing the name to _css_ to indicate this is not exported and passing</span>
<span class="hljs-comment">// different values of options can yield different variations of _css_ functions</span>
<span class="hljs-comment">// to suit different requirements example keyframes</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_css_</span>(<span class="hljs-params">styles, options</span>) </span>{
  <span class="hljs-comment">// ...same no change...</span>

  <span class="hljs-comment">// in the parsing of the style function call</span>

  parseStyles(
    <span class="hljs-comment">// style-object</span>
    options.hasKeyframes 
      ? 
        <span class="hljs-comment">// convertion to valid style-object from a keyframe-style-object</span>
        { [<span class="hljs-string">`@keyframe <span class="hljs-subst">${className}</span>`</span>]: _style_object_ }
     : 
        _style_object_,
    <span class="hljs-comment">// selector</span>
    className
  )

  <span class="hljs-comment">// ...same no change...</span>
}

<span class="hljs-comment">// final exported function from library</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> css = <span class="hljs-function">(<span class="hljs-params">style_object</span>) =&gt;</span> _css_(style_object, {});
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> keyframes = <span class="hljs-function">(<span class="hljs-params">style_object</span>) =&gt;</span> _css_(style_object, { <span class="hljs-attr">hasKeyframes</span>: <span class="hljs-literal">true</span> });
</code></pre>
<p>With <code>keyframes</code> in place, we have successfully coded our CSS-in-JS library. So as promised we have created our emotion like library; Note that emotion is way more complex and handles many different edge cases with far better optimizations.</p>
<h4 id="heading-summary-of-css-function">Summary of <code>css</code> function</h4>
<ul>
<li><code>css</code> function takes <code>style-object</code> or an array of <code>style-object</code>.</li>
<li>It stringifies this <code>style-object</code> and generates a unique hashed representational string for it, eg:<code>css-123</code>.</li>
<li>For the <code>keyframe</code> we convert <code>keyframe-style-object</code> to valid a <code>style-object</code> representation of <code>@keyframe</code> keyword.</li>
<li>These styles are then parsed. Each property in <code>style-object</code> may be on the of the following <code>At(@) rules</code>, <code>&amp;:hover</code>i.e multiple nested selector rules or <code>fontSize: '16px'</code> simple CSS properties. Each is dealt with differently as some can be block-scoped while others are global. Self-references using <code>&amp;</code> are also handled here. After the correct parsing, we generate a valid <code>CSS</code> string representation of our <code>style-object</code>.</li>
<li>This <code>CSS</code> string is added into a stylesheet in DOM and appended to <code>document.head</code>.</li>
</ul>
<p>And now as for naming this library, I will like to call it - <strong>Styler</strong> </p>
<ul>
<li><a target="_blank" href="https://github.com/vtechguys/styler">Styler GitHub</a> </li>
<li><a target="_blank" href="https://codesandbox.io/s/styler-sd2xbl">Styler Codesandbox</a></li>
<li><a target="_blank" href="https://aniketjha.dev/why-css-in-js">Why CSS-in-JS?</a></li>
<li><a target="_blank" href="https://aniketjha.dev/css-isolation-vs-abstraction">CSS: Isolation vs Abstraction</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[CSS: Isolation vs Abstraction]]></title><description><![CDATA[Total Isolation
This comes as the result of the global nature of CSS where things are leaky and thus component-based UI architectures find it difficult as cascading and global CSS causes leaks in styles across the components. For example: 
<!-- Headi...]]></description><link>https://aniketjha.dev/css-isolation-vs-abstraction</link><guid isPermaLink="true">https://aniketjha.dev/css-isolation-vs-abstraction</guid><category><![CDATA[CSS]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[CSS in JS]]></category><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Aniket Jha]]></dc:creator><pubDate>Sat, 13 Aug 2022 07:55:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1660377240488/DBj4ZmwY2.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-total-isolation">Total Isolation</h2>
<p>This comes as the result of the global nature of CSS where things are leaky and thus component-based UI architectures find it difficult as cascading and global CSS causes leaks in styles across the components. For example: </p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Heading1: Component file; applies styles inside itself. --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Some heading<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
    <span class="hljs-selector-tag">h1</span> {
        <span class="hljs-attribute">font-size</span>: <span class="hljs-number">32px</span>;
        <span class="hljs-attribute">font-weight</span>: bold;
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
<span class="hljs-comment">&lt;!-- 
 The style inside of Heading1.component.js leaks out to global affecting
 all the h1 tags.
--&gt;</span>
</code></pre>
<p>Due to the global nature of CSS, <code>h1</code> which may be inside the <code>Heading1</code> component has its own <code>style</code> but due to the global scope of CSS, it leaks out to all <code>h1</code> on the page. The component style is not scoped to the component itself thus giving birth to solutions like BEM, CSS-in-JS, and CSS Modules, which try to solve this problem by applying styles to scoped class names. For example:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- With BEM Naming convention makes sure that styles are scoped --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card__title"</span>&gt;</span>Title<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card_actions card__actions--hover"</span>&gt;</span>actions<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
    <span class="hljs-selector-class">.card</span> {
        <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">16px</span> <span class="hljs-number">24px</span>;
        <span class="hljs-attribute">display</span>: flex;
        <span class="hljs-attribute">flex-direction</span>: column;
    }
    <span class="hljs-selector-class">.card__title</span> {
        <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>;
        <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">600</span>;
    }
    <span class="hljs-selector-class">.card_actions</span> {
        <span class="hljs-attribute">display</span>: none;
    }
    <span class="hljs-selector-class">.card_actions--hover</span><span class="hljs-selector-pseudo">:hover</span> {
        <span class="hljs-attribute">display</span>: flex;
        <span class="hljs-attribute">flex-direction</span>: row;
        <span class="hljs-attribute">justify-content</span>: flex-end;
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<p>Other solutions like CSS-in-JS solve issues by creating a unique class name, you can read more about it here in <a target="_blank" href="https://aniketjha.dev/why-css-in-js">“Why CSS-in-JS?”</a> With any such solution made for isolation, there are repetitions of rules seen that do add to size but it also ensures that scope styles and prevents unintentional leaking and we should be assured that modern bundlers are smart and will only ship styles required by the page. Be mindful that CSS growth does happen in a total isolation approach.</p>
<h2 id="heading-total-abstraction">Total abstraction</h2>
<p>This embraces the global nature of CSS by creating generic, global, and reusable classes called utility or atomic classes. The solutions like <a target="_blank" href="https://tailwindcss.com/">tailwind</a> focus on using utility classes for styling and has their own build system for mitigating bundling and order issues. Each utility class remains in code forever and the smart bundlers shake off unused utility classes at build time, this makes sure the rise of CSS in the code is slow as their are utility classes covering most of the declarations and making it reusable so the growth of CSS is slow. For example:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"w-full py-4 px-6 flex flex-col"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-base font-semibold"</span>&gt;</span>Title<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden hover:flex hover:justify-end"</span>&gt;</span>actions<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
    &lt;!<span class="hljs-selector-tag">--</span> <span class="hljs-selector-tag">utility</span> <span class="hljs-selector-tag">classes</span> <span class="hljs-selector-tag">--</span>&gt;
    <span class="hljs-selector-class">.w-full</span> { <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>; }
    <span class="hljs-selector-class">.px-6</span> { <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">24px</span>; <span class="hljs-attribute">padding-right</span>: <span class="hljs-number">24px</span>; }
    <span class="hljs-selector-class">.py-4</span> { <span class="hljs-attribute">padding-top</span>: <span class="hljs-number">16px</span>; <span class="hljs-attribute">padding-bottom</span>: <span class="hljs-number">16px</span>; }
    <span class="hljs-selector-class">.flex</span> { <span class="hljs-attribute">display</span>: flex; }
    <span class="hljs-selector-class">.flex-col</span> { <span class="hljs-attribute">flex-direction</span>: column; }
    <span class="hljs-selector-class">.text-base</span> { <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>; }
    <span class="hljs-selector-class">.font-semibold</span> { <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">600</span>; }
    <span class="hljs-selector-class">.hidden</span> { <span class="hljs-attribute">display</span>: none; }
    &lt;!<span class="hljs-selector-tag">--</span> <span class="hljs-selector-tag">hover</span><span class="hljs-selector-pseudo">:flex</span> <span class="hljs-selector-tag">is</span> <span class="hljs-selector-tag">written</span> <span class="hljs-selector-tag">as</span> <span class="hljs-selector-class">.hover</span>\<span class="hljs-selector-pseudo">:flex</span> <span class="hljs-selector-tag">--</span>&gt;
    <span class="hljs-selector-class">.hover</span>\<span class="hljs-selector-pseudo">:flex</span><span class="hljs-selector-pseudo">:hover</span> { <span class="hljs-attribute">display</span>: flex; }
    <span class="hljs-selector-class">.hover</span>\<span class="hljs-selector-pseudo">:justify-content</span> { <span class="hljs-attribute">justify-content</span>: flex-end; }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<p>The above example shows how utility classes are small declarations of a rule that can be composed in an infinite number of ways to achieve many different styles without causing repetitions. </p>
<h2 id="heading-middle-ground">Middle ground</h2>
<p>The hard truth is that there is no middle ground, these two are on the opposite sides of the same axis and you cannot choose a middle ground for them. Even if you try your best you will not be able to achieve a middle ground; as the team grows there is always some dev there that will break your well-defined architecture and cause a leak or your CSS will grow or specificity wars will. </p>
<p>We should be hopeful though as efforts are being made to have a middle ground, one such effort is by <a target="_blank" href="https://www.youtube.com/watch?v=9JZHodNR184&amp;t=213s">stylex</a> a Facebook which they presented in React conf and I’m waiting for it to be made open-source to enjoy best of the both worlds.</p>
]]></content:encoded></item><item><title><![CDATA[Why CSS-in-JS?]]></title><description><![CDATA[Global and cascading nature of CSS

CSS is global by design! It is that way because we want to bring consistency across the website.

html {
    font-family: Roboto, sans-serif;
}

By writing the above code every text on your website has a font-famil...]]></description><link>https://aniketjha.dev/why-css-in-js</link><guid isPermaLink="true">https://aniketjha.dev/why-css-in-js</guid><category><![CDATA[CSS]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[React]]></category><category><![CDATA[CSS in JS]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Aniket Jha]]></dc:creator><pubDate>Fri, 12 Aug 2022 17:03:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1660321629055/ASJKEy7K4.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-global-and-cascading-nature-of-css">Global and cascading nature of CSS</h2>
<blockquote>
<p>CSS is global by design! It is that way because we want to bring consistency across the website.</p>
</blockquote>
<pre><code class="lang-css"><span class="hljs-selector-tag">html</span> {
    <span class="hljs-attribute">font-family</span>: Roboto, sans-serif;
}
</code></pre>
<p>By writing the above code every text on your website has a <code>font-family</code> set. And this is by design instead of setting <code>font-family</code> on each item. </p>
<p>This very nature of being global and cascading creates problems when styles in parents cascade into children. The problem doesn’t end there the devil called “<strong>specificity</strong>” in CSS is always there to bring you surprises.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
    <span class="hljs-selector-id">#wrapper</span> {
        <span class="hljs-attribute">background-color</span>: green;
    }

    <span class="hljs-selector-class">.background-red</span> {
        <span class="hljs-attribute">background-color</span>: red;
    }

    <span class="hljs-selector-class">.background-orange</span> {
        <span class="hljs-attribute">background-color</span>: orange;
    }

</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
// case 1
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"wrapper"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"background-orange"</span>&gt;</span>
    Box 1
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
// case 2
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>  <span class="hljs-attr">class</span>=<span class="hljs-string">"background-orange background-red"</span>&gt;</span>
    Box 2
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<ol>
<li>As the <code>id</code> has higher specificity over <code>class</code> the background color is green. </li>
<li>As the occurrence of <code>background-orange</code> is later in the style so it will override even though in <code>class</code> attribute <code>background-red</code> is used later.</li>
</ol>
<p>Scoping of CSS per component should solve the global issue of CSS. The scoping CSS problem is solved differently by different technologies. </p>
<p>Web components provide scoping CSS into shadow dom which doesn’t leak anything outside and also doesn’t let other things affect it i.e scoping it into the component and closing at the same time. Frameworks like Vue also have scoped style solutions in place. The web components provide a very strict boundary and sometimes we don’t need such a strict boundary. </p>
<p>The architecture naming of CSS classes using <strong>BEM</strong> i.e <code>.block_element--modifier</code> tries to solve the issue by following naming conventions but this isn’t absolute there are ways in which scope leaks can happen.</p>
<p>A framework like Vue and Angular has its own way of scoping styles to elements/components built in.</p>
<h2 id="heading-what-css-in-js-does-do-for-you">What CSS-in-JS does do for you?</h2>
<p>It scopes all the styles into a unique class-name thereby solving the problem of global scope. Now each item has its CSS scoped to a unique class-name. </p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { css } <span class="hljs-keyword">from</span> <span class="hljs-string">"css-in-js"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Flex</span>(<span class="hljs-params">props</span>) </span>{
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{css({</span> <span class="hljs-attr">display:</span> "<span class="hljs-attr">flex</span>" })}&gt;</span>
            {props.children}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
}
</code></pre>
<p>In the above code:</p>
<ul>
<li>The <code>css</code> function from the CSS-in-js lib takes in <code>style-object</code></li>
<li>A <code>style-object</code> is nothing but a way of writing CSS with javascript objects.</li>
</ul>
<pre><code class="lang-jsx">.text-center 
<span class="hljs-comment">// following is how css is declartion is written in a .css file -- 1</span>
{
    text-align: center;
}

<span class="hljs-comment">// the same object as style-object in javascript is written as -- 2</span>
{
    <span class="hljs-attr">textAlign</span>: <span class="hljs-string">'center'</span> <span class="hljs-comment">// split on changed casing then joined by "-" and lowercased</span>
}
</code></pre>
<ul>
<li>The <code>style-object</code> is converted into a valid CSS declaration and is scoped to a unique class-name and <code>css</code> function then returns that unique class-name.</li>
</ul>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> uniqClassName = css({ <span class="hljs-attr">textAlign</span>: <span class="hljs-string">'center'</span> });
<span class="hljs-comment">// is converted as </span>
<span class="hljs-comment">// .css-123 { text-align: center; }</span>

<span class="hljs-built_in">console</span>.log(css({ <span class="hljs-attr">textAlign</span>: <span class="hljs-string">'center'</span> });  <span class="hljs-comment">// css-123</span>
</code></pre>
<ul>
<li><p>The class-name is cached for the given <code>style-object</code> and whenever the same style is passed <code>{ textAlign: 'center' }</code>   to <code>css</code> function it will always yield <code>css-123</code> , this is an optimization step.</p>
</li>
<li><p>On the problem of specificity, it cannot solve for <code>case-1</code> because using <code>id</code> for styling indicates poor CSS architecture. For the later <code>case-2</code> it will solve it as:</p>
</li>
</ul>
<pre><code class="lang-jsx">css([ 
    { <span class="hljs-attr">display</span>: <span class="hljs-string">'flex'</span>, <span class="hljs-attr">backgroundColor</span>: <span class="hljs-string">'red'</span> }, 
    <span class="hljs-comment">// conflicting declarations backgroundColor</span>
    { <span class="hljs-attr">flexDirection</span>: <span class="hljs-string">'column'</span>, <span class="hljs-attr">backgroundColor</span>: <span class="hljs-string">'orange'</span> } 
])

<span class="hljs-comment">// styles objects in [] are merged and thus resultant style object is</span>

<span class="hljs-comment">/*

    {
        display: 'flex',
        flexDirection: 'column',
        backgroundColor: 'orange'
    }

*/</span>
</code></pre>
<p>The above solves the specificity by applying the last declaration overriding others that came before it.</p>
<h2 id="heading-problems-with-css-in-js">Problems with CSS-in-JS</h2>
<ul>
<li>Repetition of styles. Even though the two style-object vary by a very small bit there is an entirely new class-name for two. </li>
</ul>
<pre><code class="lang-jsx">css({ <span class="hljs-attr">display</span>: <span class="hljs-string">'flex'</span>, <span class="hljs-attr">flexDirection</span>: <span class="hljs-string">'row'</span> })
<span class="hljs-comment">// .css-1234 {</span>
<span class="hljs-comment">//   display: flex; // &lt;-- same declaration for display</span>
<span class="hljs-comment">//   flex-direction: row;         </span>
<span class="hljs-comment">// }</span>
css({ <span class="hljs-attr">display</span>: <span class="hljs-string">'flex'</span>, <span class="hljs-attr">flexDirection</span>: <span class="hljs-string">'column'</span> })
<span class="hljs-comment">// .css-9876 {</span>
<span class="hljs-comment">//   display: flex; // &lt;-- same declaration for display</span>
<span class="hljs-comment">//   flex-direction: column;         </span>
<span class="hljs-comment">// }</span>
</code></pre>
<p>If you notice, the two declarations vary only in values of <code>flexDirection</code> values but they will have entire different class-name, this is not a problem as it is by design to have all styles scoped uniquely under a unique class-name but the fact that the property <code>display</code> is repeated means something better can be done.</p>
<ul>
<li>We generate a unique class-name for a style-object and as the same <strong>structured</strong> style-object always returns the same class-name.</li>
</ul>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> styleObject1 = {
    <span class="hljs-attr">textAlign</span>: <span class="hljs-string">'center'</span>
};

<span class="hljs-keyword">const</span> styleObject2 = {
    <span class="hljs-attr">textAlign</span>: <span class="hljs-string">'center'</span>
};

styleObject1 === styleObject2 <span class="hljs-comment">// false: object ref is diff</span>

css(styleObject1) === css(styleObject2) <span class="hljs-comment">// true: class-name is same</span>
</code></pre>
<p>This can be only achieved by when there is a phase of <strong>stringifying</strong> the style object followed by <strong>hashing</strong> to generate a unique name.</p>
<pre><code class="lang-jsx"><span class="hljs-built_in">JSON</span>.stringify(styleObject1) === <span class="hljs-built_in">JSON</span>.stringify(styleObject2); 
<span class="hljs-comment">// true: same stringified object value for the same structured object</span>
<span class="hljs-comment">// now hashing will return the same output as the input </span>
<span class="hljs-comment">// JSON.stringify(styleObject1), JSON.stringify(styleObject2) are same</span>
</code></pre>
<p>  Depending on the logic of <strong>stringifying</strong> the object the complexity &amp; time may vary.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> object1 = { <span class="hljs-attr">a</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">b</span>: <span class="hljs-number">2</span> }; 
<span class="hljs-keyword">const</span> object2 = { <span class="hljs-attr">b</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">a</span>: <span class="hljs-number">1</span> }; <span class="hljs-comment">// &lt;-- looks same but structerly different</span>

<span class="hljs-built_in">JSON</span>.stringify(object1) === <span class="hljs-built_in">JSON</span>.stringify(object2) <span class="hljs-comment">// false: diff structure</span>
</code></pre>
<p> And so, depending on the logic of <strong>stringifying</strong> algorithm we can make <code>object1</code> and <code>object2</code> string representations look the same. It may or may not be a concern for lib to output the same class-name for same looking object and that will require some work! Most of the time it won’t be a concern as repeating a few class-name doesn’t matter much, but do note that there is always a <strong>hashing</strong> step involved usually these are quick and insecure hashing algorithms to optimize for speed.</p>
<ul>
<li><p>When using React with CSS-in-JS there is a cost of injecting styles on every render along with the phase of <strong>stringifying</strong> to generate a class-name that will happen on every render.  The new libraries like <a target="_blank" href="https://stitches.dev/">stitches</a> and <a target="_blank" href="https://vanilla-extract.style/">vanilla-extract-css</a> are looking promising by making everything build time process so this is not going to be a problem in future. A framework like <a target="_blank" href="https://tailwindcss.com/">tailwind</a> with <strong>atomic-css</strong> is something that is missing in CSS-in-JS world. I’m hopeful for <a target="_blank" href="https://youtu.be/9JZHodNR184?t=213">stylex a Facebook</a> internal <strong>atomic CSS-in-JS</strong> to provide the best of both world.</p>
</li>
<li><p>Love for preprocessors and pure CSS is not going to die that easily and it shouldn’t for the fact that CSS-in-JS is not needed for every website or it is just hard for UI-dev to wrap their minds around CSS-in-JS or view-encapsulation may just not be a problem for your project or you CSS architecture (or even using BEM naming convention) may just not have a need for it. 
Also, CSS itself is evolving and I'm hopeful for a future where scoping will be built into CSS. </p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The CSS-in-JS library solves problems of <strong>global nature</strong> of CSS and of <strong>specificity</strong> by providing <strong>scoping</strong> in a unique class-name. It has some cost attached to it i.e run-time which is being solved by order libs <a target="_blank" href="https://vanilla-extract.style/">vanilla-extract-css</a>. I'm a big fan of <a target="_blank" href="https://tailwindcss.com/">tailwind</a> and I honestly believe it is enough for your project. If you also need dynamic styles then CSS-in-JS is better over tailwind, though there are solutions like <a target="_blank" href="https://twind.dev/">twind</a> which provide a flavor of tailwind with the CSS-in-JS approach they do have all cons of any CSS-in-
JS libraries. I'm very excited about styles by Facebook and waiting for the day it will be open-sourced or CSS itself evolves to me provide scoping and be more modular, until that day comes I'm betting on CSS-in-JS with <a target="_blank" href="https://stitches.dev/">stitches</a> and <a target="_blank" href="https://vanilla-extract.style/">vanilla-extract-css</a>.</p>
]]></content:encoded></item><item><title><![CDATA[UI vs UX]]></title><description><![CDATA[I have seen a lot of confusion between these two terms among the developers. The developers tend to mix these two and for a matter of fact, these are written as UI/UX which makes it more confusing to people.

It is so confusing that this meme is not ...]]></description><link>https://aniketjha.dev/ui-vs-ux-1cb8fbb82e2</link><guid isPermaLink="true">https://aniketjha.dev/ui-vs-ux-1cb8fbb82e2</guid><category><![CDATA[Design]]></category><category><![CDATA[development]]></category><category><![CDATA[UI]]></category><category><![CDATA[UX]]></category><dc:creator><![CDATA[Aniket Jha]]></dc:creator><pubDate>Thu, 14 Jul 2022 09:17:27 GMT</pubDate><content:encoded><![CDATA[<p>I have seen a lot of confusion between these two terms among the developers. The developers tend to mix these two and for a matter of fact, these are written as UI/UX which makes it more confusing to people.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657790015220/lQnSr4UBE.jpeg" alt="This meme is not true" class="image--center mx-auto" />
It is so confusing that this meme is not true. Let us see why?</p>
<h3 id="heading-user-interface">User Interface</h3>
<p>It is the elements on screen that you see like button, spinner, progress bar, slider, etc. UI deals with how the look their color, their shape, etc. The UI is the first thing people see on your website and it is a foremost important thing as its the first impression. Richer the UI greater is the impression.</p>
<h3 id="heading-user-experience">User Experience</h3>
<p>It is the flow of elements on your screen eg. a button leading to navigation is the flow of the app. UX people connect the parts of UI to make an experience for the user that is easy to use the system. The flow of information between screens and tasks are logical to understand.</p>
<h3 id="heading-wrap-up">Wrap Up</h3>
<p>User Interface is all about the look and feel of the app. How creatively information can be displayed it takes a lot of creativity to make a great UI.</p>
<p>User experience is determined by how easy or difficult it is to interact with the user interface elements that the UI designers have created.</p>
<p>UX designer decides how the user interface works while the UI designer decides how the user interface looks. This is a very collaborative process, and the two design teams tend to work closely together. As the UX team is working out the flow of the app, how all of the buttons navigate you through your tasks, and how the interface efficiently serves up the information user’s need, the UI team is working on how all of these interface elements will appear on screen.<br />Correct meme from <a target="_blank" href="http://www.patrickhansen.com/2017/09/01/ui-vs-ux-design-meme-problem/">Patrix Hansen</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1644169943604/Kkl1Vkpmk.jpeg" alt="UI vs UX" class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Allow to enter particular characters only]]></title><description><![CDATA[Sometimes we want to make validations on an input box for characters that user can type. And other characters will not be entertained in the input box.

Question: Make a input box that accepts digits and spaces only. Also, care for copy-paste (Ctrl +...]]></description><link>https://aniketjha.dev/javascript-dom-allow-to-enter-particular-characters-only</link><guid isPermaLink="true">https://aniketjha.dev/javascript-dom-allow-to-enter-particular-characters-only</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Validation]]></category><category><![CDATA[HTML5]]></category><category><![CDATA[forms]]></category><dc:creator><![CDATA[Aniket Jha]]></dc:creator><pubDate>Tue, 12 Jul 2022 18:20:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1657649822732/obE3Eii6P.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Sometimes we want to make validations on an input box for characters that user can type. And other characters will not be entertained in the input box.</p>
<blockquote>
<p>Question: Make a input box that accepts <em>digits</em> and <em>spaces</em> only. Also, care for copy-paste (Ctrl +V ) of invalid characters.</p>
</blockquote>
<p>The first step is to register an event on the input tag. But what event type? 🤔 We are typing characters into it so <code>keypress</code> the event looks fine.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"input"</span>/&gt;</span>
</code></pre>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> input = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'input'</span>);  
<span class="hljs-keyword">var</span> currentInputValue = <span class="hljs-string">''</span>;  
input.addEventListener(<span class="hljs-string">'keypress'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">inputKeypressHandler</span>(<span class="hljs-params">e</span>) </span>{  
    <span class="hljs-comment">// keypress event on input box is listened here and this function is triggered  </span>
    <span class="hljs-comment">// which key is pressed, keyPressed = e.which || e.keyCode;   </span>
    <span class="hljs-keyword">const</span> key = e.which || e.keyCode;  
    <span class="hljs-comment">// key code corresponds to digits 0-9 or space then okay👍🏼  </span>
    <span class="hljs-comment">// 0-9 key code is 48-57  </span>
    <span class="hljs-comment">// space keycode is 32  </span>
    <span class="hljs-keyword">const</span> SPACE = <span class="hljs-number">32</span>; <span class="hljs-comment">// May be just stored somewhere  </span>
    <span class="hljs-keyword">const</span> ZERO = <span class="hljs-number">48</span>;  
    <span class="hljs-keyword">const</span> NINE = <span class="hljs-number">57</span>;  
    <span class="hljs-comment">// valid digit is b/w 0-9 thus invalid will be lt 0 or gt 9  </span>
    <span class="hljs-keyword">const</span> isNotValidDigit = key &lt; ZERO || key &gt; NINE;  
    <span class="hljs-comment">// if key is not a space or not a digit prevent this event  </span>
    <span class="hljs-keyword">if</span> (key != SPACE || ( isNotValidDigit ) ) {  
        e.preventDefault();  
    }  
});
</code></pre>
<p>This is a pretty good solution but this doesn’t prevent paste cheats. And that is because the <code>keypress</code> event only records key pressed inside the input box. A better event type is required. <code>input</code> it runs on all input ways including copy paste and drag.</p>
<pre><code class="lang-js"><span class="hljs-keyword">var</span> currentInputValue = <span class="hljs-string">''</span>;  
input.addEventListener(<span class="hljs-string">'input'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">inputInputEventHandler</span>(<span class="hljs-params">e</span>) </span>{  
    <span class="hljs-comment">// use target of event to get value of input  </span>
    <span class="hljs-keyword">const</span> target = e.target;  
    <span class="hljs-comment">// we can use regex to check if current input value  </span>
    <span class="hljs-comment">// is valid input  </span>
    <span class="hljs-keyword">const</span> DIGITS_SPACE_REGEX = <span class="hljs-regexp">/^[0-9\s]*$/</span>;  
    <span class="hljs-comment">// test if target.value or value of input box now is valid.  </span>
    <span class="hljs-comment">// if value is valid then update currentInputValue   </span>
    <span class="hljs-comment">// target.value else its is not value and we will  </span>
    <span class="hljs-comment">// ignore this target.value and replace it with   </span>
    <span class="hljs-comment">// previously valid value currentInputValue  </span>
    DIGITS_SPACE_REGEX.test(target.value)   
        ? ( currentInputValue = target.value )   
        : ( target.value = currentInputValue );  
});
</code></pre>
<p>This solves our problem of paste but there is one problem here. Say you paste something <code>Ctrl/Cmd + V</code> your current cursor position will be lost and moved to starting. This must not happen and you must be able to retain cursor position.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Track cursor position  </span>
<span class="hljs-comment">// cursor position is changed when you type something  </span>
<span class="hljs-keyword">const</span> cursorState = {};  
input.addEventListener(<span class="hljs-string">'keydown'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">inputKeydownHandler</span>(<span class="hljs-params">e</span>) </span>{  
    <span class="hljs-keyword">const</span> target = e.target;  
    <span class="hljs-comment">// record the start and end  </span>
    cursorState.selectionStart = target.selectionStart;  
    cursorState.selectionEnd = target.selectionEnd;  
});
</code></pre>
<p>now in <code>input</code> handler</p>
<pre><code><span class="hljs-comment">// modify  </span>
DIGITS_SPACE_REGEX.test(target.<span class="hljs-built_in">value</span>)   
        ? ( currentInputValue <span class="hljs-operator">=</span> target.<span class="hljs-built_in">value</span> )   
        : ( target.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span> currentInputValue );  
 <span class="hljs-comment">// to  </span>
 <span class="hljs-keyword">if</span> (DIGITS_SPACE_REGEX.test(target.<span class="hljs-built_in">value</span>)) {  
     currentValue <span class="hljs-operator">=</span> target.<span class="hljs-built_in">value</span>;  
 }  
 <span class="hljs-keyword">else</span> {  
    target.<span class="hljs-built_in">value</span> <span class="hljs-operator">=</span> current.<span class="hljs-built_in">value</span>;  
    <span class="hljs-comment">// restore cursor state  </span>
    target.setSelectionRange(  
        cursorState.selectionStart,  
        cursorState.selectionEnd  
    );  
 }
</code></pre><p><a target="_blank" href="https://codepen.io/vtechguys/pen/JjYLmQd">Demo 👨‍💻</a></p>
]]></content:encoded></item><item><title><![CDATA[Method of primitive]]></title><description><![CDATA[Let’s start with a piece of code:
const name = "aniket";
name.toUpperCase(); // ANIKET

The name is a primitive but we are able to access a method on it as if it were some sort of object. But we know that primitive isn’t an object.What is the story h...]]></description><link>https://aniketjha.dev/method-of-primitive-206fbee0c5f</link><guid isPermaLink="true">https://aniketjha.dev/method-of-primitive-206fbee0c5f</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[datastructure]]></category><category><![CDATA[Objects]]></category><dc:creator><![CDATA[Aniket Jha]]></dc:creator><pubDate>Tue, 12 Jul 2022 05:20:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1657603134841/wKJUTcL5L.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let’s start with a piece of code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> name = <span class="hljs-string">"aniket"</span>;
name.toUpperCase(); <span class="hljs-comment">// ANIKET</span>
</code></pre>
<p>The <code>name</code> is a primitive but we are able to access a method on it as if it were some sort of object. But we know that primitive isn’t an object.<br />What is the story here?🧐</p>
<p>Primitive are simple values stored in memory, those are lightweight and extremely fast. Whereas an object is a collection of the key, value pairs, it is heavy but it allows to access some utility properties associated with the object that is very useful. The javascript people faced the dilemma where they wanted to put primitive for being lightweight and fast but also wanted to allow access useful methods on primitives.</p>
<p>The solution the came up with was:</p>
<p><em>As soon as the engine reaches line 2 it sees that you are trying to do property access on primitive, but as primitive itself doesn’t have methods on them. It momentarily wraps the primitive value into a corresponding type wrapper object that has these methods on them and that object exposes us the properties which we can use, as soon as the method is done executing it returns the result of the operation in a new memory space and deletes this wrapper object.</em></p>
<h4 id="heading-constructors-function">Constructors function</h4>
<p>The constructor function <code>String, Number, Boolean</code> is for internal use only. Languages like Java allows us to explicitly creates a wrapper object that is also possible with JavaScript but those are not recommended and are for internal use only. A lot of things can go crazy if we use those.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Insane Use 🙅‍♂️ Not recommended</span>
<span class="hljs-keyword">const</span> age = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Number</span>(<span class="hljs-number">22</span>);
<span class="hljs-keyword">typeof</span> age; <span class="hljs-comment">// "object" 😱</span>
<span class="hljs-comment">// Sane Use 😍</span>
<span class="hljs-keyword">const</span> age = <span class="hljs-built_in">Number</span>(<span class="hljs-string">"22"</span>);
<span class="hljs-comment">// explicit type conversion</span>
</code></pre>
<h4 id="heading-recap-with-a-question">Recap with a question</h4>
<p>Explain the console output in <code>strict</code> and non-strict mode?</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> name = <span class="hljs-string">"Aniket"</span>;
name.last = <span class="hljs-string">"Jha"</span>;
<span class="hljs-built_in">console</span>.log(name.last);
</code></pre>
<p>In <code>strict</code> mode on line 2, the engine sees that we are trying to create a property on internal momentarily created internal wrapper object so there occurs an error. For a non-strict mode the engine on line 2, allows you to create a property on momentarily created wrapper object but this object is thrown out of memory as soon as line 2 is done executing. On line 3 a new wrapper object is created momentarily but as this is different from previous it doesn't have the<code>last</code>property and thus <code>undefined</code> is the output.</p>
<h4 id="heading-conclusions">Conclusions</h4>
<p>The primitive is indeed a simple value but the engine treats primitive especially if it sees there is property access on it by wrapping it in wrapper object and exposing us with useful methods and properties.</p>
]]></content:encoded></item><item><title><![CDATA[Loadables - a simple way to load data in React]]></title><description><![CDATA[The real-world app involves data loading via some API and showing UI based on the states of the API. For example, while data is loading, you may show a loader animation, but on error, you may show an error UI. This fairly simple-looking task ends up ...]]></description><link>https://aniketjha.dev/loadables-a-simple-way-to-load-data-in-react</link><guid isPermaLink="true">https://aniketjha.dev/loadables-a-simple-way-to-load-data-in-react</guid><category><![CDATA[React]]></category><category><![CDATA[design patterns]]></category><dc:creator><![CDATA[Aniket Jha]]></dc:creator><pubDate>Sat, 02 Jul 2022 10:05:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1656756119202/B4sKbg3P2.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The real-world app involves data loading via some API and showing UI based on the states of the API. For example, while data is loading, you may show a loader animation, but on error, you may show an error UI. This fairly simple-looking task ends up getting complex super fast and is more difficult to maintain with all the spaghetti code for UI synchronization. So here I propose the <strong>loadable</strong> pattern to simplify data loading and synchronize the UI with it.</p>
<p>In this example, we are going to load a list of todos. Here we are using react-redux as a state management solution. Below we will see how to create a store and reducer with react-redux. However, you can directly skip to <a class="post-section-overview" href="#heading-loadableloadable">"loadables"</a> if you familiar with react-redux-context store.</p>
<h3 id="heading-create-react-redux-context-storereact-context-store"><a class="post-section-overview" href="#react-context-store">Create react-redux context store</a></h3>
<p>Let's start by creating a react-redux-context-store for storing our todos. The following sample is taken from <a target="_blank" href="https://react-redux.js.org/api/hooks#custom-context">react-redux</a>.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// [filename: todo.store.jsx]</span>

<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> {
  Provider,
  createStoreHook,
  createDispatchHook,
  createSelectorHook,
 <span class="hljs-keyword">from</span> <span class="hljs-string">"react-redux"</span>;
<span class="hljs-keyword">import</span> { createStore } <span class="hljs-keyword">from</span> <span class="hljs-string">"redux"</span>;
<span class="hljs-comment">// reducer for the state</span>
<span class="hljs-keyword">import</span> { reducer } <span class="hljs-keyword">from</span> <span class="hljs-string">"./store.reducer"</span>

<span class="hljs-comment">// react context store</span>
<span class="hljs-keyword">const</span> TodoContext = React.createContext(<span class="hljs-literal">null</span>)

<span class="hljs-comment">// create redux state selector and dispatch from context</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> useTodoStore = createStoreHook(TodoContext)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> useTodoDispatch = createDispatchHook(TodoContext)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> useTodoSelector = createSelectorHook(TodoContext)

<span class="hljs-comment">// create redux store from the reducer</span>
<span class="hljs-keyword">const</span> todoStore = createStore(reducer)

<span class="hljs-comment">// create store provider wrap subtree</span>
<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TodoStoreProvider</span>(<span class="hljs-params">{ children }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Provider</span> <span class="hljs-attr">context</span>=<span class="hljs-string">{TodoContext}</span> <span class="hljs-attr">store</span>=<span class="hljs-string">{todoStore}</span>&gt;</span>
      {children}
    <span class="hljs-tag">&lt;/<span class="hljs-name">Provider</span>&gt;</span></span>
  )
}
</code></pre>
<p>After creating a store provider we are going to create <code>store.reducer.js</code> where we define the reducer and actions for the store.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// [filename: todo.reducer.js]</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> loadNext = <span class="hljs-function">() =&gt;</span> ({ <span class="hljs-attr">type</span>: <span class="hljs-string">'load_next'</span> });
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addTodos = <span class="hljs-function">(<span class="hljs-params">{ todos, total }</span>) =&gt;</span> ({ <span class="hljs-attr">type</span>: <span class="hljs-string">'add_todos'</span>, <span class="hljs-attr">payload</span>: { todos, total } });
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> setLoading = <span class="hljs-function">(<span class="hljs-params">loading</span>) =&gt;</span> ({ <span class="hljs-attr">type</span>: <span class="hljs-string">'set_loading'</span>, <span class="hljs-attr">payload</span>: { loading }  });

<span class="hljs-keyword">const</span> InitState = {
 <span class="hljs-attr">status</span>: <span class="hljs-string">'idle'</span>, <span class="hljs-comment">// idle | pending | resolve | reject </span>
 <span class="hljs-attr">todos</span>: [],
 <span class="hljs-attr">total</span>: <span class="hljs-number">0</span>,
 <span class="hljs-attr">skip</span>: <span class="hljs-number">0</span>,
 <span class="hljs-attr">limit</span>: <span class="hljs-number">10</span>
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> reducer = <span class="hljs-function">(<span class="hljs-params">state = InitState, action</span>) =&gt;</span> {
  <span class="hljs-keyword">switch</span> (action.type) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">'load_next'</span>: {
       <span class="hljs-keyword">if</span> (state.todos.length &lt; state.total &amp;&amp; state.status !== <span class="hljs-string">'pending'</span>) {
          <span class="hljs-keyword">return</span> {
             ...state,
             <span class="hljs-attr">status</span>:  <span class="hljs-string">'pending'</span>
          };
       }
       <span class="hljs-keyword">return</span> state;
    }
    <span class="hljs-keyword">case</span> <span class="hljs-string">'add_todos'</span>: {
      <span class="hljs-keyword">return</span> {
          ...state,
          <span class="hljs-attr">status</span>: <span class="hljs-string">'resolve'</span>,
          <span class="hljs-attr">todos</span>: [...state.todos, ...action.payload.todos],
          <span class="hljs-attr">total</span>: state.total + action.payload.todos.length 
      };
    }
    <span class="hljs-keyword">case</span> <span class="hljs-string">'set_loading'</span>: {
      <span class="hljs-keyword">return</span> {
          ...state,
          <span class="hljs-attr">status</span>: action.payload.loading
      };
    }
    <span class="hljs-attr">default</span>: {
      <span class="hljs-keyword">return</span> state;
    }
  }
};
</code></pre>
<h3 id="heading-loadableheading-loadableloadable"><a class="post-section-overview" href="#heading-loadableloadable">Loadable</a></h3>
<p>Loadables are react components that wrap all data loading logic in it and update the store.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// [filename: App.js]</span>

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">TodoStoreProvider</span>&gt;</span>
      {/* Loadable holds all data loading logic*/}
      <span class="hljs-tag">&lt;<span class="hljs-name">TodoLoadable</span>&gt;</span>
        {/* Render todos */}
      <span class="hljs-tag">&lt;/<span class="hljs-name">TodoLoadable</span>&gt;</span>
     <span class="hljs-tag">&lt;/<span class="hljs-name">TodoStoreProvider</span>&gt;</span>
   <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
 );
</code></pre>
<p>Now let's create a loadable:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// [filename: Todo.loadable.js]</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TodoLoadable</span>(<span class="hljs-params">props</span>) </span>{
  <span class="hljs-comment">// react-redux state slice selector</span>
  <span class="hljs-keyword">const</span> skip = useTodoSelector(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> state.skip);
  <span class="hljs-keyword">const</span> limit = useTodoSelector(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> state.limit);
  <span class="hljs-keyword">const</span> todoDispatch = useTodoDispatch();
  <span class="hljs-comment">// load data</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    todoDispatch(setLoading(<span class="hljs-string">'pending'</span>));
    api({ skip, limit })
      .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> todoDispatch({ <span class="hljs-attr">todos</span>: res.todos, <span class="hljs-attr">total</span>: res.total }))
      .catch(<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> todoDispatch(setLoading(<span class="hljs-string">'reject'</span>)));
  }, [skip, limit]);
  <span class="hljs-comment">// render child</span>
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;&gt;</span>{props.children}<span class="hljs-tag">&lt;/&gt;</span></span>
}
</code></pre>
<p>The point to note here is that the loading logic is completely placed inside the loadable and the children can utilize the store to sync UI state accordingly. <code>IsVisible</code> is a utility component that can be used to render things conditionally.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// [filename: IsVisible.utility.jsx]</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">IsVisible</span>(<span class="hljs-params">{ visible, unmountOnExit, ...props }</span>) </span>{   
  <span class="hljs-keyword">if</span> (unmountOnExit &amp;&amp; !visible) {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
  }
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> {<span class="hljs-attr">...props</span>} <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>  <span class="hljs-attr">...props.style</span>, <span class="hljs-attr">display:</span> <span class="hljs-attr">visible</span> ? '<span class="hljs-attr">flex</span>' <span class="hljs-attr">:</span> '<span class="hljs-attr">none</span>'  }} /&gt;</span></span>
}
</code></pre>
<p>We can use the <code>IsVisible</code> utility component to create state synced UI.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// [filename: Todo.jsx]</span>

<span class="hljs-keyword">const</span> <span class="hljs-built_in">Error</span> = <span class="hljs-function">() =&gt;</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Error<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
<span class="hljs-keyword">const</span> Loader = <span class="hljs-function">() =&gt;</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">CircularProgress</span> <span class="hljs-attr">size</span>=<span class="hljs-string">"small"</span> /&gt;</span></span>
<span class="hljs-keyword">const</span> Todos = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> todos = useTodoSelector(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> state.todos);
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{todos.map((todo) =&gt; <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{todo}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>)}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">IsErrorVisible</span>(<span class="hljs-params">props</span>) </span>{
  <span class="hljs-keyword">const</span> isError = useTodoSelector(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> state.status === <span class="hljs-string">'reject'</span>);
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">IsVisible</span> {<span class="hljs-attr">...props</span>} <span class="hljs-attr">visible</span>=<span class="hljs-string">{isError}</span> /&gt;</span></span>
}

....more IsVisible <span class="hljs-keyword">for</span> all API status <span class="hljs-string">'reject'</span> | <span class="hljs-string">'resolve'</span> | <span class="hljs-string">'pending'</span> | <span class="hljs-string">'idle'</span>
</code></pre>
<p>Now with the help of this <code>IsVisible</code>, we can render UI according to the state of API.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// [filename: App.js]</span>

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">TodoStoreProvider</span>&gt;</span>
      {/* Loadable holds all data loading logic*/}
      <span class="hljs-tag">&lt;<span class="hljs-name">TodoLoadable</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">IsErrorVisible</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">ErrorUI</span> /&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">IsErrorVisible</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">IsTodoVisible</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">Todos</span> /&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">IsTodoVisible</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">IsLoaderVisible</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">Loader</span> /&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">IsLoaderVisible</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">TodoLoadable</span>&gt;</span>
     <span class="hljs-tag">&lt;/<span class="hljs-name">TodoStoreProvider</span>&gt;</span>
   <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
 );
</code></pre>
<p>This is how <code>loadable</code> along with <code>IsVisible</code> utility makes it super easy to load data in react and make a code simple to write and understand. Here is a link to demo <a target="_blank" href="https://codesandbox.io/s/loadables-9fc1j6">Codesandbox.</a></p>
]]></content:encoded></item><item><title><![CDATA[Should you default to React.memo() or useMemo()?]]></title><description><![CDATA[You might have faced slow renders in react application? When such a situation happens we find ourselves inclined to use React.memo or useMemo. We use React.memo to bail out of re-rendering by wrapping subtree in React.memo. This works pretty well as ...]]></description><link>https://aniketjha.dev/should-you-default-to-reactmemo-or-usememo</link><guid isPermaLink="true">https://aniketjha.dev/should-you-default-to-reactmemo-or-usememo</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[React]]></category><dc:creator><![CDATA[Aniket Jha]]></dc:creator><pubDate>Sun, 06 Feb 2022 17:04:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1644163862377/Ek1Twbj7_.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You might have faced slow renders in react application? When such a situation happens we find ourselves inclined to use <code>React.memo</code> or <code>useMemo</code>. We use <code>React.memo</code> to bail out of re-rendering by wrapping subtree in <code>React.memo.</code> This works pretty well as an optimization patch but with big real-world apps using it mindlessly can make you suffer <em>“death by thousand cuts”</em> and you may end up wrapping everything that you think is slow with <code>React.memo.</code> </p>
<p>With this comes using <code>useMemo</code> and <code>useCallback</code> which you may use for <a target="_blank" href="https://en.wikipedia.org/wiki/Memoization">memoized</a> computational values, functions, and handlers. This adds to overall code complexity and you may end up running more code for React to determine changed values, compare them and memoize them. Sometimes this might be the only solution but there are approaches that you can try before you <code>memoize</code> things. </p>
<p>Consider the following code sample:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-comment">// [App.js]</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [name, setName] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{name}</span> 
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setName(e.target.value)} /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">SlowSubtree</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SlowSubtree</span>(<span class="hljs-params"></span>) </span>{
  sleep(<span class="hljs-number">500</span>); <span class="hljs-comment">// try increasing time here 💣</span>
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Artifically Slow subtree<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;
}

<span class="hljs-comment">// [utils.js]</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sleep</span>(<span class="hljs-params">time</span>) </span>{
  <span class="hljs-keyword">const</span> exitAt = <span class="hljs-built_in">Date</span>.now() + time;
  <span class="hljs-keyword">while</span> (exitAt &gt; <span class="hljs-built_in">Date</span>.now()) {
    <span class="hljs-comment">// simulate expensive subtree</span>
  }
}
</code></pre>
<p>In the code example, we have artificially simulated an expensive sub-tree with <code>&lt;SlowSubtree /&gt;</code> component. Which gets re-rendered on a change in input. As we type in input we set the <code>name</code> state thus causing a re-render of the <code>App</code> component, which then renders <code>&lt;SlowSubtree /&gt;</code>. The quick fix here is wrapping SlowSubtreecomponent in a <code>React.memo</code> as shown below:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { memo } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-comment">// [App.js]</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SlowSubtreeComponent</span>(<span class="hljs-params"></span>) </span>{
  sleep(<span class="hljs-number">500</span>);
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Artifically Slow subtree<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
}

<span class="hljs-keyword">const</span> SlowSubtree = memo(SlowSubtreeComponent);
</code></pre>
<p><code>React.memo()</code> is a quick fix but can we avoid using it? Following are some approaches:</p>
<h3 id="heading-debounce-set-state">Debounce set-state</h3>
<p>In the example, we are setting the <code>name</code> state with every keystroke and causing re-rendering each time input changes, setting the state on every keystroke is wastage here. What we can do is we can debounce set state calls to prevent rendering with each keystroke. I consider this as a bit of a <strong><em>hacky</em></strong> approach but I’ve put this here to bring this to your notice.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { 
  useState, 
  useMemo, 
  useLayoutEffect, 
  useRef 
} <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-comment">// [App.js]</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [name, setName] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> debounceOnChange = useDebounceFn(
    <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setName(e.target.value)
  );

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{debounceOnChange}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">SlowSubtree</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SlowSubtree</span>(<span class="hljs-params"></span>) </span>{
  sleep(<span class="hljs-number">500</span>); <span class="hljs-comment">// try increasing time here 💣</span>
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Artifically Slow subtree<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;
}

<span class="hljs-comment">// [utils.js]</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sleep</span>(<span class="hljs-params">time</span>) </span>{
  <span class="hljs-keyword">const</span> exitAt = <span class="hljs-built_in">Date</span>.now() + time;
  <span class="hljs-keyword">while</span> (exitAt &gt; <span class="hljs-built_in">Date</span>.now()) {
    <span class="hljs-comment">// simulate expensive subtree</span>
  }
}

<span class="hljs-comment">// [hooks.js]</span>
<span class="hljs-keyword">import</span> debounce <span class="hljs-keyword">from</span> <span class="hljs-string">"lodash.debounce"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useDebounceFn</span>(<span class="hljs-params">callbackFn, delay = <span class="hljs-number">500</span></span>) </span>{
  <span class="hljs-keyword">const</span> callbackFnRef = useRef(callbackFn);

  useLayoutEffect(<span class="hljs-function">() =&gt;</span> {
    callbackFnRef.current = callbackFn;
  });

  <span class="hljs-keyword">return</span> useMemo(
    <span class="hljs-function">() =&gt;</span> debounce(
       <span class="hljs-function">(<span class="hljs-params">...args</span>) =&gt;</span> callbackFnRef.current(...args), delay),
    [delay]
  );
}
</code></pre>
<h3 id="heading-state-relocation">State relocation</h3>
<p>Note that the <code>SlowSubtree</code> the component renders because of a state change in the parent component. The changing part here is <code>name</code> state with <code>&lt;input/&gt;</code> while <code>SlowSubtree</code> is not changing. We can split and move state down in its separate component like shown below:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-comment">// [App.js]</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [name, setName] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">NameInput</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">SlowSubtree</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">NameInput</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [name, setName] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">return</span>  (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> 
      <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> 
      <span class="hljs-attr">value</span>=<span class="hljs-string">{name}</span> 
      <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setName(e.target.value)} 
    /&gt;</span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SlowSubtree</span>(<span class="hljs-params"></span>) </span>{
  sleep(<span class="hljs-number">500</span>); <span class="hljs-comment">// try increasing time here 💣</span>
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Artifically Slow subtree<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;
}

<span class="hljs-comment">// [utils.js]</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sleep</span>(<span class="hljs-params">time</span>) </span>{
  <span class="hljs-keyword">const</span> exitAt = <span class="hljs-built_in">Date</span>.now() + time;
  <span class="hljs-keyword">while</span> (exitAt &gt; <span class="hljs-built_in">Date</span>.now()) {
    <span class="hljs-comment">// simulate expensive subtree</span>
  }
}
</code></pre>
<h3 id="heading-render-as-a-child">Render as a child</h3>
<p>It is not required to move the state down in its own <code>NameInput</code> component we can also move the state up and leverage a pattern called<em> render as child.</em>
This pattern is very similar to the render props approach but instead of passing components to a render prop, we use <code>props.children</code> instead. Here we will lift the state up in its own component and wrap <code>SlowSubtree</code> component with it.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-comment">// [App.js]</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">NameComponent</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">SlowSubtree</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">NameComponent</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">NameComponent</span>(<span class="hljs-params">props</span>) </span>{
  <span class="hljs-keyword">const</span> [name, setName] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> 
         <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> 
         <span class="hljs-attr">value</span>=<span class="hljs-string">{name}</span> 
         <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setName(e.target.value)} 
       /&gt;
      {props.children}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SlowSubtree</span>(<span class="hljs-params"></span>) </span>{
  sleep(<span class="hljs-number">500</span>); <span class="hljs-comment">// try increasing time here 💣</span>
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Artifically Slow subtree<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;
}

<span class="hljs-comment">// [utils.js]</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sleep</span>(<span class="hljs-params">time</span>) </span>{
  <span class="hljs-keyword">const</span> exitAt = <span class="hljs-built_in">Date</span>.now() + time;
  <span class="hljs-keyword">while</span> (exitAt &gt; <span class="hljs-built_in">Date</span>.now()) {
    <span class="hljs-comment">// simulate expensive subtree</span>
  }
}
</code></pre>
<p>When name state changed <code>NameComponent</code> re-render but as it still gets the same <code>children</code> prop as last time so React doesn’t need to visit <code>SlowSubtreesubtree.</code> And as a result <code>&lt;SlowSubtree /&gt;</code> doesn’t re-render.</p>
<p>I have personally used this approach many times to prevent the re-rendering of child subtree. This pattern is also used in layout components where the wrapper decided the layout and styles of its children. For example <a target="_blank" href="https://mui.com/components/cards/">Material-UI Card component</a>. The layout component may or may not maintain the state but they generally receive the child as a prop or render-props.</p>
<h3 id="heading-conclusion">Conclusion:</h3>
<p>Before you use a <code>React.memo()</code> or <code>useMemo()</code> again you should stop and think to see if you can split part that changes from the parts that don’t change. So take into account if state relocation can help before you settle with the <code>memo.</code></p>
]]></content:encoded></item><item><title><![CDATA[CSS variables vs ThemeContext]]></title><description><![CDATA[The light mode and dark mode are gaining popularity and more apps are offering these theme switching. This theme switching looks cool but is difficult to implement and hard to get right. There are many libraries(emotion.js) that let you do this with ...]]></description><link>https://aniketjha.dev/css-variables-vs-themecontext</link><guid isPermaLink="true">https://aniketjha.dev/css-variables-vs-themecontext</guid><category><![CDATA[React]]></category><category><![CDATA[CSS]]></category><category><![CDATA[UI]]></category><category><![CDATA[performance]]></category><dc:creator><![CDATA[Aniket Jha]]></dc:creator><pubDate>Tue, 29 Jun 2021 07:38:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1644169909365/RXnb8kVWH.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The light mode and dark mode are gaining popularity and more apps are offering these theme switching. This theme switching looks cool but is difficult to implement and hard to get right. There are many libraries(<a target="_blank" href="https://emotion.sh/docs/introduction">emotion.js</a>) that let you do this with ease by giving a <code>ThemeProvider</code> which is nothing but a React component that provides theme context. These libraries use CSS-in-JS which is a beautiful way of writing CSS with javascript.</p>
<p>I have been using CSS-in-JS for most of my projects and I’m in love with it but over time CSS has improved, the browsers have matured and support for CSS is better than before. The cost of implementing theme switching with CSS-in-JS libraries is considerably more than using browser standard CSS variables.</p>
<p>Let’s take the example of CSS-in-JS theme switching.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { jsx, ThemeProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"@emotion/react"</span>;
<span class="hljs-keyword">import</span> styled <span class="hljs-keyword">from</span> <span class="hljs-string">"@emotion/styled"</span>;
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> themes = {
  <span class="hljs-attr">light</span>: {
    <span class="hljs-attr">colors</span>: {
      <span class="hljs-attr">primary</span>: <span class="hljs-string">"#48ff00"</span>,
      <span class="hljs-attr">background</span>: <span class="hljs-string">"#fff"</span>
    }
  },
  <span class="hljs-attr">dark</span>: {
    <span class="hljs-attr">colors</span>: {
      <span class="hljs-attr">primary</span>: <span class="hljs-string">"#ff0000"</span>,
      <span class="hljs-attr">background</span>: <span class="hljs-string">"#000"</span>
    }
  }
};

<span class="hljs-keyword">const</span> Heading1 = styled.h1(<span class="hljs-function">(<span class="hljs-params">{ theme }</span>) =&gt;</span> ({
  <span class="hljs-attr">color</span>: theme.colors.primary,
  <span class="hljs-attr">backgroundColor</span>: theme.colors.background
}));

<span class="hljs-keyword">const</span> Paragraph = styled.p(<span class="hljs-function">(<span class="hljs-params">{ theme }</span>) =&gt;</span> ({
  <span class="hljs-attr">color</span>: theme.colors.primary,
  <span class="hljs-attr">backgroundColor</span>: theme.colors.background
}));

<span class="hljs-keyword">const</span> Div = styled.div(<span class="hljs-function">(<span class="hljs-params">{ theme }</span>) =&gt;</span> ({
  <span class="hljs-attr">backgroundColor</span>: theme.colors.background
}));

<span class="hljs-keyword">const</span> Button = styled.button(<span class="hljs-function">(<span class="hljs-params">{ theme }</span>) =&gt;</span> ({
  <span class="hljs-attr">color</span>: theme.colors.primary,
  <span class="hljs-attr">backgroundColor</span>: theme.colors.background
}));

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [isLight, setIsLight] = useState(<span class="hljs-literal">true</span>);
  <span class="hljs-keyword">const</span> activeTheme = isLight ? <span class="hljs-string">"light"</span> : <span class="hljs-string">"dark"</span>;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ThemeProvider</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{themes[activeTheme]}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsLight((prev) =&gt; !prev)}&gt;
            {activeTheme}
          <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Heading1</span>&gt;</span>CSS In JS<span class="hljs-tag">&lt;/<span class="hljs-name">Heading1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Paragraph</span>&gt;</span>
          Emotion is a library designed for writing css 
        styles with JavaScript. It provides powerful 
        and predictable style composition in addition 
        to agreat developer experience with features 
        such as source maps, labels,and testing utilities. 
        Both string and object styles are supported.
        <span class="hljs-tag">&lt;/<span class="hljs-name">Paragraph</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ThemeProvider</span>&gt;</span></span>
  );
}
</code></pre>
<p>That’s the beauty of CSS-in-js it’s just javascript. The developer experience is pretty amazing with such API. However the user experience takes a hit when there are many components on the page, so switching the theme takes a while sometimes a noticeable delay. This leads to a poor user experience which is bad for our brand and business. Here is <a target="_blank" href="https://y8l81.csb.app/">codesandbox</a> for the CSS-in-JS example.</p>
<p>Now let’s do it with CSS variables.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { jsx } <span class="hljs-keyword">from</span> <span class="hljs-string">"@emotion/react"</span>;
<span class="hljs-keyword">import</span> styled <span class="hljs-keyword">from</span> <span class="hljs-string">"@emotion/styled"</span>;
<span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./theme.css"</span>;

<span class="hljs-comment">/*
  theme.css

  body[data-theme="light"] {
    --color--primary: #48ff00;
    --color--background: #fff;
  }

  body[data-theme="dark"] {
    --color-primary: #ff0000;
    --color-background: #000;
  }
*/</span>

<span class="hljs-keyword">const</span> Heading1 = styled.h1({
  <span class="hljs-attr">color</span>: <span class="hljs-string">"var(--color-primary)"</span>,
  <span class="hljs-attr">backgroundColor</span>: <span class="hljs-string">"var(--color-background)"</span>
});

<span class="hljs-keyword">const</span> Paragraph = styled.p({
  <span class="hljs-attr">color</span>: <span class="hljs-string">"var(--color-primary)"</span>,
  <span class="hljs-attr">backgroundColor</span>: <span class="hljs-string">"var(--color-background)"</span>
});
<span class="hljs-keyword">const</span> Div = styled.div({
  <span class="hljs-attr">backgroundColor</span>: <span class="hljs-string">"var(--color-background)"</span>
});

<span class="hljs-keyword">const</span> Button = styled.button({
  <span class="hljs-attr">color</span>: <span class="hljs-string">"var(--color-primary)"</span>,
  <span class="hljs-attr">backgroundColor</span>: <span class="hljs-string">"var(--color-background)"</span>
});

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ThemeToggler</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [isLight, setIsLight] = useState(<span class="hljs-string">"light"</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">document</span>.body.dataset.theme = isLight ? <span class="hljs-string">"light"</span> : <span class="hljs-string">"dark"</span>;
  }, [isLight]);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsLight((prev) =&gt; !prev)}&gt;
      {isLight ? "light" : "dark"}
    <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ThemeToggler</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Heading1</span>&gt;</span>CSS Variable<span class="hljs-tag">&lt;/<span class="hljs-name">Heading1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Paragraph</span>&gt;</span>
        Emotion is a library designed for writing css 
        styles with JavaScript. It provides powerful 
        and predictable style composition in addition 
        to agreat developer experience with features 
        such as source maps, labels,and testing utilities. 
        Both string and object styles are supported.
      <span class="hljs-tag">&lt;/<span class="hljs-name">Paragraph</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Here the developer experience may suffer because of loss of static typing on <code>theme</code> object but the user experience is considerably better. Also, a developer doesn’t need to learn API <code>styled.button(({**theme**}) =&gt; ({ ...styles }))</code> where we create a function accepting <code>theme</code> and returning styles. Here is a link to <a target="_blank" href="https://codesandbox.io/s/css-var-bfo2z">codesandbox</a>.</p>
<h4 id="heading-react-profiler-matrix">React profiler matrix⚛️</h4>
<p><strong>CSS-in-JS way of theme switching</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1644169905616/o74YM6ilj.png" alt /></p>
<p>CSS-in-JS way of theme switching</p>
<p><strong>CSS variables of theme switching</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1644169907166/EYnvLYWjG.png" alt /></p>
<p>CSS variable way of theme switching</p>
<p>By seeing the above two screenshots it is very clear that using CSS variable is better than using CSS-in-JS way. A better developer experience can be achieved by a hybrid of two. Following gives you the ability for static type on <code>theme</code> object as <code>theme.colors.primary</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { jsx } <span class="hljs-keyword">from</span> <span class="hljs-string">"@emotion/react"</span>;
<span class="hljs-keyword">import</span> styled <span class="hljs-keyword">from</span> <span class="hljs-string">"@emotion/styled"</span>;
<span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { theme } <span class="hljs-keyword">from</span> <span class="hljs-string">"./theme"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./theme.css"</span>;
<span class="hljs-comment">/*
  theme.css

  body[data-theme="light"] {
    --color--primary: #48ff00;
    --color--background: #fff;
  }

  body[data-theme="dark"] {
    --color-primary: #ff0000;
    --color-background: #000;
  }
*/</span>

<span class="hljs-comment">/*
  theme.js
  export const theme = {
    colors: {
      primary: "var(--color-primary)",
      background: "var(--color-background)"
    }
  };
*/</span>

<span class="hljs-keyword">const</span> Heading1 = styled.h1({
  <span class="hljs-attr">color</span>: theme.colors.primary,
  <span class="hljs-attr">backgroundColor</span>: theme.colors.background
});

<span class="hljs-keyword">const</span> Paragraph = styled.p({
  <span class="hljs-attr">color</span>: theme.colors.primary,
  <span class="hljs-attr">backgroundColor</span>: theme.colors.background
});

<span class="hljs-keyword">const</span> Div = styled.div({
  <span class="hljs-attr">backgroundColor</span>: theme.colors.background
});

<span class="hljs-keyword">const</span> Button = styled.button({
  <span class="hljs-attr">color</span>: theme.colors.primary,
  <span class="hljs-attr">backgroundColor</span>: theme.colors.background
});

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ThemeToggler</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [isLight, setIsLight] = useState(<span class="hljs-string">"light"</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">document</span>.body.dataset.theme = isLight ? <span class="hljs-string">"light"</span> : <span class="hljs-string">"dark"</span>;
  }, [isLight]);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsLight((prev) =&gt; !prev)}&gt;
      {" "}
      {isLight === "light" ? "dark" : "light"}
    <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ThemeToggler</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Heading1</span>&gt;</span>CSS var and CSS in JS<span class="hljs-tag">&lt;/<span class="hljs-name">Heading1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Paragraph</span>&gt;</span>
        Emotion is a library designed for writing css 
        styles with JavaScript. It provides powerful 
        and predictable style composition in addition 
        to agreat developer experience with features 
        such as source maps, labels,and testing utilities. 
        Both string and object styles are supported.
      <span class="hljs-tag">&lt;/<span class="hljs-name">Paragraph</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Div</span>&gt;</span></span>
  );
}
</code></pre>
<h4 id="heading-conclusion">Conclusion</h4>
<p>CSS-in-JS is awesome but it comes with the cost of injecting styles with every render and theme switching using <code>ThemeContext</code> is not performant especially if there are a large number of components on a screen. Theme switching is very performant with CSS variables. Let’s use more CSS variables to develop awesome web apps themes.</p>
<p>Credit: Image by <a target="_blank" href="https://www.ailonwebs.com/en/blog/web-page-design/dark-mode-and-light-mode/index.php">ailonwebs.com</a></p>
]]></content:encoded></item><item><title><![CDATA[Proxy and Reflect in Javascript | Part 2]]></title><description><![CDATA[In the previous post, we discussed Proxy in detail. In this post, we will build upon that knowledge and learn some more.
Reflect helps in the creation of Proxy and somewhat allows us to play with internal methods [[Get]] and [[Set]]. Below are some r...]]></description><link>https://aniketjha.dev/proxy-and-reflect-in-javascript-part-2</link><guid isPermaLink="true">https://aniketjha.dev/proxy-and-reflect-in-javascript-part-2</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[javascript framework]]></category><dc:creator><![CDATA[Aniket Jha]]></dc:creator><pubDate>Sun, 01 Nov 2020 10:44:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1644169921961/_j9JS1BFO.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the <a target="_blank" href="https://aniketjha.dev/proxy-in-javascript-part-1"><em>previous</em></a> post, we discussed Proxy in detail. In this post, we will build upon that knowledge and learn some more.</p>
<p>Reflect helps in the creation of Proxy and somewhat allows us to play with internal methods <code>[[Get]]</code> and <code>[[Set]]</code>. Below are some reflect methods:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1644169920073/ceLPJXJ9Q.png" alt /></p>
<p>Let us look at a code example:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> user = {};

Relect.set(user, <span class="hljs-string">'name'</span>, <span class="hljs-string">'Aniket Jha'</span>); <span class="hljs-comment">// [[Set]]</span>

<span class="hljs-built_in">console</span>.log(user.name); <span class="hljs-comment">// Aniket Jha</span>
</code></pre>
<p>Reflect allow us to call operators as functions also there is a reflect method for any proxy traps having the same name and arguments.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> user = {};

user = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Proxy</span>(user, {
  get(target, prop, receiver) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`GET Trap &gt; Target: <span class="hljs-subst">${target}</span> Prop <span class="hljs-subst">${prop}</span> Receiver <span class="hljs-subst">${receiver}</span>`</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Reflect</span>.get(target, prop, receiver);
  },
  set(target, prop, value, receiver) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`SET Trap &gt; Target <span class="hljs-subst">${traget}</span> Prop <span class="hljs-subst">${prop}</span> Value <span class="hljs-subst">${value}</span> Receiver <span class="hljs-subst">${receiver}</span>`</span>);
    <span class="hljs-keyword">return</span> Relect.set(target, prop, value, receiver);
  },
});
</code></pre>
<p>The Reflect methods work nicely with proxy to ensure that traps output and what we expected is the same. Following is an example:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> user = {
  <span class="hljs-attr">_name</span>: <span class="hljs-string">'User'</span>,
  <span class="hljs-keyword">get</span> <span class="hljs-title">name</span>() {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>._name;
  }
};
<span class="hljs-keyword">let</span> proxyUserObj = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Proxy</span>(user, {
  get(target, prop) {
    <span class="hljs-keyword">return</span> target[prop]; <span class="hljs-comment">// Note we didn't used reflect here.</span>
  },
});
<span class="hljs-keyword">let</span> admin = {
  <span class="hljs-attr">__proto__</span>: proxyUserObj,
  <span class="hljs-attr">_name</span>: <span class="hljs-string">'Admin'</span>
};
<span class="hljs-built_in">console</span>.log(admin.name); <span class="hljs-comment">// Admin or User 🤔 </span>
<span class="hljs-comment">// admin.name ?</span>
<span class="hljs-comment">// `name` is not found on admin obj</span>
<span class="hljs-comment">// so it will go up in prototype chain</span>
<span class="hljs-comment">// Note prototype chain is proxyfied object `proxyUserObj`</span>
<span class="hljs-comment">// it finds `name` property(getter property) on `proxyUserObj`</span>
<span class="hljs-comment">// resolving for name property trigger proxy `get trap`</span>
<span class="hljs-comment">// the arguments that are passed to proxy get trap</span>
<span class="hljs-comment">// target =&gt; user</span>
<span class="hljs-comment">// prop =&gt; 'name'</span>
<span class="hljs-comment">// as trap return traget[prop] i.e user['name'] so `this === user`</span>
<span class="hljs-comment">// and returned value is `User` 😱 which was not expected</span>
<span class="hljs-comment">// to prevent it from happening `receiver` argument is requried</span>
<span class="hljs-comment">// and we can leave it to `Reflect.get(target, props, receiver)` to</span>
<span class="hljs-comment">// correctly resolve properties for us.</span>
</code></pre>
<p>We saw an example of how Reflect is useful for dealing with this Proxy gotcha. I always write<code>return Reflect.get(…arguments);</code> 😎. Reflect is awesome to enhance proxy and use it correctly. More on proxy on <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy">MDN</a>.  </p>
]]></content:encoded></item><item><title><![CDATA[Proxy in JavaScript | Part 1]]></title><description><![CDATA[A Proxy object wraps another object and intercepts operations on it. While intercepting operations like reading, writing properties on the object, the proxy may choose to handle these operations and modify results.
Proxy
Syntax: let proxy = new Proxy...]]></description><link>https://aniketjha.dev/proxy-in-javascript-part-1</link><guid isPermaLink="true">https://aniketjha.dev/proxy-in-javascript-part-1</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Javascript library]]></category><dc:creator><![CDATA[Aniket Jha]]></dc:creator><pubDate>Sat, 08 Aug 2020 15:12:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1644169930031/KQYbaTDtI.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A Proxy object wraps another object and intercepts operations on it. While intercepting operations like reading, writing properties on the object, the proxy may choose to handle these operations and modify results.</p>
<h4 id="heading-proxy">Proxy</h4>
<p>Syntax: <code>let proxy = new Proxy(target, handler);</code></p>
<p><code>target</code>: the object that has to be proxied.<br /><code>handler</code>: the proxy configuration object, it may register <code>traps</code>. A <code>trap</code> is a handler for a particular kind of operation. By registering a <code>trap</code> handler it can intercept the operation and do its own thing.</p>
<p>If there is a <code>trap</code> for the operation on<code>handler</code> only then the operation will be trapped and handled by proxy else operation directly occurs on the object itself.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> user = {}; 
<span class="hljs-comment">// target object -- object to be proxied</span>
<span class="hljs-keyword">let</span> userProxy = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Proxy</span>(user, {}); 
<span class="hljs-comment">// proxy for user, note empty handler</span>

<span class="hljs-comment">// operations on proxy</span>
userProxy.name = <span class="hljs-string">'Aniket'</span>; 
<span class="hljs-comment">// set operation</span>
<span class="hljs-comment">// should be intercepted by</span>
<span class="hljs-comment">// `set` trap on handler</span>
<span class="hljs-comment">// no `set` trap registerd so </span>
<span class="hljs-comment">// operations are performed on object itself </span>
<span class="hljs-built_in">console</span>.log(userProxy.name); <span class="hljs-comment">// 'Aniket;</span>
<span class="hljs-comment">// get opertaion</span>
<span class="hljs-comment">// should be intercepted by `get` trap</span>
<span class="hljs-comment">// no `get` trap registerd so opertaion </span>
<span class="hljs-comment">// is performed on object directly</span>
<span class="hljs-built_in">console</span>.log(user.name); <span class="hljs-comment">// 'Aniket'</span>
<span class="hljs-comment">// Thus we can see name property </span>
<span class="hljs-comment">// directly on target itself</span>
</code></pre>
<p>For most of the operations on objects, there are “<strong>Internal Methods</strong>” in JavaScript that describes how operations work at a low level, what proxy trap does is that it can intercept these methods and do its own thing.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1644169925826/SLUwTScvxD.png" alt="Proxy visualisation" /></p>
<p>Below we show some of the “Internal Methods” and their corresponding proxy traps.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1644169928061/cuRPHpYWf.png" alt="Proxy trap and corresponding Internal method" /></p>
<p>Internal Methods have some rules that our traps must follow, for eg: <code>set</code> the trap must return <code>true</code> if property setting was success else <code>false.[[GetPrototypeOf]]</code> must always return the target’s prototype when applied on proxy as well.</p>
<h4 id="heading-the-problem-statement">The problem statement</h4>
<blockquote>
<p>It is common practice to use <code>*_*</code> is in the beginning of the property name to denote a private property. You cannot get/set/loop this property. Write a proxy to achieve this.</p>
</blockquote>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> user = {
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Aniket'</span>,
  <span class="hljs-attr">_password</span>: <span class="hljs-string">'Password'</span>, <span class="hljs-comment">// private property</span>
  isCorrectPassword(pswd) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>._password === pswd;
    <span class="hljs-comment">// `this` here is a gotcha</span>
  },
};
</code></pre>
<h4 id="heading-set-trap">“set” trap</h4>
<p>We will register a <code>set</code> trap on the handler to intercept write operation on the object.</p>
<p>Syntax: <code>set(target, prop, value, receiver).</code></p>
<p><code>target</code> : target object.<br /><code>prop</code> : property name that is being set.<br /><code>value</code> : the value of the property to be set.<br /><code>receiver</code> : the object that is utilised as in getters.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> userProxy = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Proxy</span>(user, {
  set(target, prop, value, reciver) { 
    <span class="hljs-comment">// intercepts property write</span>
    <span class="hljs-keyword">if</span> (prop.startsWith(<span class="hljs-string">'_'</span>)) {
      <span class="hljs-comment">// check if property name start with `_`</span>
      <span class="hljs-comment">// then it is a private property so</span>
      <span class="hljs-comment">// don't allow to write or create a property</span>
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Access denied 💣 "</span>);
    } <span class="hljs-keyword">else</span> {
      target[prop] = val;
      <span class="hljs-comment">// normally write on object</span>
      <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>; <span class="hljs-comment">// must return true [[Set]] rule</span>
    }
  }
});
</code></pre>
<h4 id="heading-get-trap">“get” trap</h4>
<p>We will register a <code>get</code> trap to prevent direct access <code>user._password</code> to private property. Also, we have to ensure that <code>isCorrectpassword</code> works correctly as it does indirect access <code>this._password</code>.</p>
<p>Syntax: <code>get(target, property, receiver)</code>.<br />The arguments mean the same as above.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> userProxy = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Proxy</span>(user, {
  get(target, prop, receiver) {
    <span class="hljs-comment">// intercept property read</span>
    <span class="hljs-keyword">if</span> (prop.startsWith(<span class="hljs-string">'_'</span>)) {
      <span class="hljs-comment">// if property name starts with `_` then</span>
      <span class="hljs-comment">// we don't allow to read and raise an error</span>
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Access denied 💣 "</span>);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-comment">// the property value may be a function or something else</span>
      <span class="hljs-keyword">let</span> propValue = target[prop];
      <span class="hljs-comment">// in case it is a function</span>
      <span class="hljs-comment">// it may have `this` inside it</span>
      <span class="hljs-comment">// where `this` will ref to `userProxy` </span>
      <span class="hljs-comment">// as it will be invoked as `userProxy.isCorrectPassword(pswd)` </span>
      <span class="hljs-comment">// so `this == userProxy` but that will 🔥 our code</span>
      <span class="hljs-comment">// so we need to make sure that our function `this` ref `user`</span>
      <span class="hljs-comment">// and so we bind it</span>
      <span class="hljs-keyword">return</span> (
        <span class="hljs-keyword">typeof</span> propValue === <span class="hljs-string">"function"</span> 
          ? propValue.bind(target) : propValue
      );
    }
  }  
});
</code></pre>
<h4 id="heading-deleteproperty-trap">“deleteProperty” trap</h4>
<p>We will register <code>deleteProperty</code> so that we can't delete a private property.<br />Syntax: <code>deleteProperty(target, property)</code></p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> userProxy = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Proxy</span>(user, {
  deleteProperty(target, prop) {
    <span class="hljs-comment">// deleteProperty trap to handle property delete</span>
    <span class="hljs-keyword">if</span>(prop.startsWith(<span class="hljs-string">'_'</span>)) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Access denied 💣 "</span>);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-comment">// delete property on object</span>
      <span class="hljs-keyword">delete</span> target[prop];
      <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>; <span class="hljs-comment">// successfully deleted</span>
    }
  }
});
</code></pre>
<h4 id="heading-ownkeys-trap">“ownKeys” trap</h4>
<p><code>for..in, Object.keys, Object.values</code> and other methods utilise an “Internal Method” called <code>[[OwnPropertyKeys]]</code> to get a list of keys. For eg:<br /><code>Object.getOwnPropertyNames()</code> to get a list of non-symbol keys,<br /><code>Object.getOwnPropertySymbols()</code> to get a list of symbol keys,<br /><code>Object.keys()</code> to get a list of non-symbol enumerable keys, etc.</p>
<p>They all call <code>[[OwnPropertyKeys]]</code> but tweak it a bit to return keys according to their use case. So we will register <code>ownKeys(target)</code> trap to return only public keys.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> userProxy = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Proxy</span>(user, {
  ownKeys(target) {
    <span class="hljs-comment">// ownKeys will return a list of keys</span>
    <span class="hljs-comment">// we must get keys on target then filter</span>
    <span class="hljs-comment">// to remove all private keys</span>
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Object</span>.keys(target).filter(<span class="hljs-function">(<span class="hljs-params">key</span>)=&gt;</span>!key.startsWith(<span class="hljs-string">'_'</span>));
  }
});
</code></pre>
<p><strong>Note:</strong> Our traps must follow the rules defined for “Internal Method”. The rule defined for <code>ownKeys</code> with <code>Object.keys()</code> is that it must return non-symbol enumerable keys. Look at the example below to understand this gotcha.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> userProxy = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Proxy</span>(user, {
  ownKeys(target) {
    <span class="hljs-comment">// this will return list of keys </span>
    <span class="hljs-comment">// and the calling method (Object.keys) tweak this list</span>
    <span class="hljs-comment">// to select and return a list of </span>
    <span class="hljs-comment">// non-symbolic and enumberable: true keys</span>
    <span class="hljs-comment">// thus for each item in list returned by ownKeys</span>
    <span class="hljs-comment">// it will only select item which is </span>
    <span class="hljs-comment">// non-symbolic and enumberable: true</span>
    <span class="hljs-keyword">return</span> [<span class="hljs-string">'email'</span>, <span class="hljs-string">'phone'</span>];
  }
});
<span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">Object</span>.keys(userProxy)); <span class="hljs-comment">// [] empty 😱 gotcha</span>

<span class="hljs-comment">// solution </span>
<span class="hljs-keyword">let</span> userProxy = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Proxy</span>(user, {
  ownKeys(target) {
    <span class="hljs-comment">// Object.keys will check property descriptor</span>
    <span class="hljs-comment">// for each key returned by ownKeys and see if</span>
    <span class="hljs-comment">// enumberable: true</span>
    <span class="hljs-keyword">return</span> [<span class="hljs-string">'email'</span>, <span class="hljs-string">'phone'</span>];
  },
  getOwnPropertyDescriptor(target, prop) {
    <span class="hljs-comment">// checking for enumberablity of keys</span>
    <span class="hljs-comment">// is accessing its descriptor and seeing</span>
    <span class="hljs-comment">// if enumberable is true</span>
    <span class="hljs-comment">// here we are returning descriptor obj</span>
    <span class="hljs-comment">// with enumberable true in all cases</span>
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">enumerable</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">configurable</span>: <span class="hljs-literal">true</span>,
    };
  }
});
</code></pre>
<h4 id="heading-has-trap">“has” trap</h4>
<p>This trap work with the <code>in</code> operator that intercepts the <code>[[hasProperty]]</code> Internal Method. Let’s register a <code>has(target, property)</code> trap.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> range = {
  <span class="hljs-attr">from</span>: <span class="hljs-number">1</span>,
  <span class="hljs-attr">to</span>: <span class="hljs-number">10</span>,
};
<span class="hljs-comment">// we need to check if 5 in range</span>
<span class="hljs-comment">// 5 in range if 5 &gt;= range.from &amp;&amp; 5 &lt;= range.to</span>
<span class="hljs-keyword">let</span> rangeProxy = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Proxy</span>(range, {
  has(target, prop) {
    <span class="hljs-comment">// 5 &gt;= 1 &amp;&amp; 5 &lt;= 10</span>
    <span class="hljs-keyword">return</span> prop &gt;= target.from &amp;&amp; prop &lt;= target.to;
  },
});
<span class="hljs-built_in">console</span>.log(<span class="hljs-number">5</span> <span class="hljs-keyword">in</span> rangeProxy); <span class="hljs-comment">// true</span>
</code></pre>
<h4 id="heading-apply-trap">“apply” trap</h4>
<p>Until now all examples we have seen were on objects and now we will see an example of <code>function as target</code>.</p>
<p>Syntax: <code>apply(target, thisArgs, args)</code>.<br /><code>thisArgs</code> : it is the value of <code>this</code><br /><code>args</code> : it is a list of arguments for function</p>
<pre><code class="lang-js"><span class="hljs-comment">// Let us write a function `delay`</span>
<span class="hljs-comment">// that delay exceution of any </span>
<span class="hljs-comment">// function `f` by `ms` milliseconds</span>


<span class="hljs-comment">// solution 1 closure way</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">delay</span>(<span class="hljs-params">f, ms</span>) </span>{
   <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">name</span>) </span>{ <span class="hljs-comment">// *</span>
    <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> f.bind(<span class="hljs-built_in">this</span>, <span class="hljs-built_in">arguments</span>), ms);
   }
}

<span class="hljs-keyword">var</span> hi = <span class="hljs-function">(<span class="hljs-params">name</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Hi! '</span> + name);
};
<span class="hljs-built_in">console</span>.log(hi.length); <span class="hljs-comment">// 1</span>
<span class="hljs-comment">// function.length returns number a params </span>
hi = delay(hi, <span class="hljs-number">3000</span>);
<span class="hljs-comment">// hi is now function at line *</span>
<span class="hljs-built_in">console</span>.log(hi.length); <span class="hljs-comment">// 0 😱</span>
<span class="hljs-comment">// we lost orignal hi function </span>
<span class="hljs-comment">// and function at line * has no params so 0 </span>
hi(<span class="hljs-string">'Aniket'</span>); <span class="hljs-comment">// 'Hi! Aniket'</span>
<span class="hljs-comment">// runs after 3s</span>

<span class="hljs-comment">// solution 2 proxy way</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">delay</span>(<span class="hljs-params">f, ms</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Proxy</span>(f, {
    apply(target, thisArgs, args) {
      <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> target.bind(thisArgs, args), ms);
    }
  });
}
<span class="hljs-keyword">var</span> hi = <span class="hljs-function">(<span class="hljs-params">name</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Hi! '</span> + name);
};
<span class="hljs-built_in">console</span>.log(hi.length); <span class="hljs-comment">// 1</span>
hi = delay(hi, <span class="hljs-number">3000</span>);
<span class="hljs-built_in">console</span>.log(hi.length); <span class="hljs-comment">// 1 😎</span>
hi(<span class="hljs-string">'Aniket'</span>); <span class="hljs-comment">// 'Hi! Aniket'</span>
</code></pre>
<h4 id="heading-the-end">The End</h4>
<p>Now teach the Proxy you learnt here to your friend for whom you have put proxy 😂. Here is the next part of the post <a target="_blank" href="https://aniketjha.dev/proxy-and-reflect-in-javascript-part-2">Part 2</a>. Stay tuned for more content.</p>
]]></content:encoded></item><item><title><![CDATA[Javascript: Array Methods | Mutating vs Non-Mutating]]></title><description><![CDATA[In this article, we are going to look at a few common array operations in their mutable and non-mutable versions. Add, Delete, and Replace are the most common operations, and we will take a look at those operations. 
In this article, we will exploit ...]]></description><link>https://aniketjha.dev/javascript-array-methods-mutating-vs-non-mutating-8606d9b78c77</link><guid isPermaLink="true">https://aniketjha.dev/javascript-array-methods-mutating-vs-non-mutating-8606d9b78c77</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[array]]></category><category><![CDATA[array methods]]></category><category><![CDATA[immutable]]></category><dc:creator><![CDATA[Aniket Jha]]></dc:creator><pubDate>Sun, 24 May 2020 14:08:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1656770272273/0rARVHj4i.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article, we are going to look at a few common array operations in their mutable and non-mutable versions. Add, Delete, and Replace are the most common operations, and we will take a look at those operations. </p>
<p>In this article, we will exploit methods like <code>array.map()</code> to produce non-mutating versions. This is not an exhaustive listing, we will keep ourselves limited to basic manipulations.</p>
<p><em>I will assign array to <code>const</code> to show non-mutating aspect and <code>let</code>  as mutating.</em> </p>
<p>Though you can always mutate array assign to <code>const</code> but I like to it that way keep for developer indication.</p>
<h3 id="heading-add-mutating">Add: Mutating</h3>
<p>The easiest way to add an item to array is <code>array.push()</code> and <code>array.unshift()</code>.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Note: using `let` here to indicate that this array will be mutated.</span>

<span class="hljs-keyword">let</span> array = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>];  
array.push(<span class="hljs-number">6</span>); <span class="hljs-comment">// [1, 2, 3, 4, 5, 6];  </span>
array.unshift(<span class="hljs-number">10</span>);<span class="hljs-comment">// [10, 1, 2, 3, 4, 5, 6];</span>
</code></pre>
<p><code>array.push()</code> adds an item to the end and <code>array.unshift()</code> adds an item to the front of the array.</p>
<h3 id="heading-add-non-mutating">Add: Non-Mutating</h3>
<p>There are two ways to do so <code>array.concat()</code> and <code>…array</code> spread operator.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Note use `const` to indicate that this will not be mutated  </span>
<span class="hljs-comment">// concat</span>
<span class="hljs-keyword">const</span> array1 = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>];  
<span class="hljs-keyword">const</span> array2 = array.concat(<span class="hljs-number">6</span>);  <span class="hljs-comment">// [1, 2, 3, 4, 5, 6];</span>
<span class="hljs-comment">// spread</span>
<span class="hljs-keyword">const</span> array3 = [...array1, <span class="hljs-number">6</span>]; <span class="hljs-comment">// [1, 2, 3, 4, 5, 6];  </span>
<span class="hljs-keyword">const</span> array4 = [<span class="hljs-number">10</span>, ...array1]; <span class="hljs-comment">// [10, 1, 2, 3, 4, 5];</span>
</code></pre>
<p><code>array1.concat(item1, item2, …)</code> the <code>concat</code> method will merge all items from array1 and items passed as params and create a new array with them. While the <code>…</code> spread operator will essentially take all items out from array and place them in a new array context.</p>
<h3 id="heading-remove-mutating">Remove: Mutating</h3>
<p>There are two methods <code>array.pop()</code> and <code>array.shift()</code></p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> array = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>];  
array.pop();  <span class="hljs-comment">// [1, 2, 3, 4] &gt; delete from end and return deleted item  </span>
array.shift();  <span class="hljs-comment">// [2, 3, 4]  &gt; delete from front and return deleted item</span>
</code></pre>
<p><code>array.pop()</code> delete an item from the end and return deleted item. <code>array.shift()</code> delete an item from the front and return deleted item.</p>
<p>There is one important method to manipulate array i.e <code>array.splice()</code>. It mutates the array. <code>splice()</code> takes 2 important params, first being the starting index and second being the number of items to be removed. <code>splice</code> will remove items from array directly. for eg. <code>splice(0, 2)</code> will remove two items starting from index 0.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> array = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>];  
array.splice(<span class="hljs-number">0</span>, <span class="hljs-number">2</span>); <span class="hljs-comment">// [3, 4, 5];</span>
</code></pre>
<h3 id="heading-remove-non-mutating">Remove: Non-Mutating</h3>
<p>The removing or any type of filtering is done by <code>array.filter()</code>, the <code>filter()</code> is among the coolest non-mutating method on the array. It takes a function that is called over each item in the array during that it has to do some filtering where if it returns <code>true</code> then the item will be included in new array and return <code>false</code> if items has to be thrown away.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> array1 = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>];  
<span class="hljs-keyword">const</span> array2 = array1.filter(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> item !== <span class="hljs-number">5</span>);   
<span class="hljs-comment">// will filter any item i.e not equal to 5</span>
</code></pre>
<p>Another very important method is <code>array.slice()</code>. Remember this is not <code>array.splice()</code>, they are different <code>array.slice()</code> will return new array i.e its is not mutating. It is very similar to slice for how its is used. It takes 2 important params, the first is starting index where copying should begin and second is end index where copy should end, it is not inclusive. It copy items between those index and returned them in a new array.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> array1 = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>];  
<span class="hljs-keyword">const</span> array2 = array1.slice(<span class="hljs-number">0</span>, <span class="hljs-number">2</span>); <span class="hljs-comment">// [1,2];  </span>
<span class="hljs-comment">// if no args provided ti  will copy the whole array</span>
</code></pre>
<h3 id="heading-replace-mutating">Replace: Mutating</h3>
<p>Array <code>splice</code> method is very interesting method because not only it can remove items but also add items to the array directly. The third parameters and onwards basically mean items that need to be inserted to array.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> array = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>];  
array.splice(<span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">10</span>, <span class="hljs-number">12</span>); <span class="hljs-comment">// [1, 2, 10, 12, 4, 5];</span>
</code></pre>
<p>splice will remove 1 item starting index 2 and then insert 10 and 12 from the same position.</p>
<h3 id="heading-replace-or-transform-non-mutating">Replace | Transform: Non-mutating</h3>
<p>The mighty method <code>array.map()</code> is very useful as it can transform array. Map method takes a function that is called on each item of the array and it must return an item that has to be put into the new array.</p>
<pre><code>const array1 <span class="hljs-operator">=</span> [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>];  
const array2 <span class="hljs-operator">=</span> array1.map((item) <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> {  
  <span class="hljs-keyword">if</span> (item <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">3</span>) {  
    <span class="hljs-keyword">return</span> <span class="hljs-number">10</span>;    
  }  
  <span class="hljs-keyword">return</span> item;  
}); <span class="hljs-comment">// [1, 2, 10, 4, 5];</span>

<span class="hljs-comment">// Map as transformation  </span>
const mutilpliedByTwo <span class="hljs-operator">=</span> array1.map((item) <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> item \<span class="hljs-operator">*</span> <span class="hljs-number">2</span>);   
<span class="hljs-comment">// [2, 4, 6, 8, 10];</span>
</code></pre>]]></content:encoded></item><item><title><![CDATA[Expo Barcode Scanner]]></title><description><![CDATA[Before we start we will update our node, npm and expo cli. Just to use all the latest features. Now create a new expo project. Choose the project with everything previously setup. We choose this app to get quickly started.
nvm use 12 // install versi...]]></description><link>https://aniketjha.dev/expo-barcode-scanner-69b4f4122da2</link><guid isPermaLink="true">https://aniketjha.dev/expo-barcode-scanner-69b4f4122da2</guid><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[React Native]]></category><category><![CDATA[Expo]]></category><category><![CDATA[Android]]></category><dc:creator><![CDATA[Aniket Jha]]></dc:creator><pubDate>Fri, 08 Nov 2019 12:07:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1660556030603/p8jDMO8bP.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Before we start we will update our node, npm and expo cli. Just to use all the latest features. Now create a new expo project. Choose the project with everything previously setup. We choose this app to get quickly started.</p>
<pre><code>nvm <span class="hljs-keyword">use</span> <span class="hljs-number">12</span> // <span class="hljs-keyword">install</span> <span class="hljs-keyword">version</span> <span class="hljs-number">12</span> - latest@<span class="hljs-number">2019</span>  
npm <span class="hljs-keyword">install</span> -g expo-cli // <span class="hljs-keyword">install</span> expo cli <span class="hljs-keyword">globally</span>  
expo init // <span class="hljs-keyword">create</span> a <span class="hljs-keyword">project</span>  
// <span class="hljs-keyword">choose</span> the javascript <span class="hljs-keyword">project</span> <span class="hljs-keyword">with</span> navigation setup
</code></pre><iframe src="https://www.youtube.com/embed/OT7Lprq-xPE?feature=oembed" width="640" height="480"></iframe>

<p>Final product demo</p>
<h3 id="heading-scanner-screen">Scanner Screen</h3>
<p>In the app, as I am using the minimal setup project I am using the default <code>HomeScreen</code> as <code>ScannerScreen</code>. We are using a React class component you may simply use functional components with hooks for state management.</p>
<p>The Scanner screen is a class-based component. The state has two important properties one <code>hasCameraPermissions</code> for if the screen has permission to access the camera and the second property is<code>isScanned</code> for if something has been scanned or not. Initially, the state of <code>ScannerScreen</code> for <code>hasCameraPermissions</code> is null. Null means that we are requesting for permission. And state <code>isScanned</code> is false means nothing is scanned as of now.</p>
<p>As the scanner requires camera permission thus we need to ask for camera permission from the user.<br />Permission is an asynchronous task and we must ask for permission as soon as this component is mounted so <code>componentDidMount</code> seems like a good place to start. Note Permission asking is asynchronous so we have to make <code>componentDidMount</code> a <code>async</code> function. If Camera permission is given then <code>hasCameraPermissions</code> is set to true and we may successfully render our barcode scanner and open camera else if permission is declined <code>*hasCameraPermissions*</code> is set to false and we render declined permission message.</p>
<p>Next, we have a function for handling a successfully scanned barcode. If the bar code is scanned this function will be called. Our function <code>*handleBarCodeScanned*</code> is passed as callback to <code>*onBarCodeScanned*</code> prop on <code>*BarCodeScanner*</code> component. In <code>*handleBarCodeScanned*</code> function we receive a scan object as an argument which has two important properties, one is the <code>*type*</code> which means what type of bar code was scanned and the other is <code>*data*</code> which is the encrypted data in our barcode. We will destructure these properties as others are irrelevant to us. In our case of <code>*handleBarCodeScanned*</code> <em>function,</em> we are just navigating to the <code>*DecodeScreen*</code> passing <em>code data</em> as params. The <code>DecodeScreen</code> then displays the data.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;


<span class="hljs-keyword">import</span> { Container, Spinner, TextH3 } <span class="hljs-keyword">from</span> <span class="hljs-string">"../UI"</span>;

<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> Permissions <span class="hljs-keyword">from</span> <span class="hljs-string">'expo-permissions'</span>;

<span class="hljs-keyword">import</span> { BarCodeScanner } <span class="hljs-keyword">from</span> <span class="hljs-string">'expo-barcode-scanner'</span>;

<span class="hljs-keyword">import</span> {<span class="hljs-built_in">window</span>} <span class="hljs-keyword">from</span> <span class="hljs-string">"../constants/Layout"</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ScannerScreen</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span></span>{
  <span class="hljs-keyword">static</span> navigationOptions = {
    <span class="hljs-attr">header</span>: <span class="hljs-literal">null</span>
  }
  <span class="hljs-comment">// Component State</span>
  state = {
    <span class="hljs-attr">hasCameraPermission</span>: <span class="hljs-literal">null</span>, <span class="hljs-comment">// if app has permissions to acess camera</span>
    <span class="hljs-attr">isScanned</span>: <span class="hljs-literal">false</span> <span class="hljs-comment">// scanned</span>
  }
  <span class="hljs-keyword">async</span> componentDidMount() {
    <span class="hljs-comment">// ask for camera permission</span>
    <span class="hljs-keyword">const</span> { status } = <span class="hljs-keyword">await</span> Permissions.askAsync(Permissions.CAMERA);
    <span class="hljs-built_in">console</span>.log(status);
    <span class="hljs-built_in">this</span>.setState({ <span class="hljs-attr">hasCameraPermission</span>: status === <span class="hljs-string">"granted"</span> ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span> });
  }


  handleBarCodeScanned = <span class="hljs-function">(<span class="hljs-params">{ type, data }</span>) =&gt;</span> {
      <span class="hljs-comment">// Do something here</span>
      <span class="hljs-built_in">this</span>.props.navigation.navigate(<span class="hljs-string">'Decode'</span>, {
        <span class="hljs-attr">data</span>: data 
      });
  }
  render(){
    <span class="hljs-keyword">const</span> { hasCameraPermission, isScanned } = <span class="hljs-built_in">this</span>.state;
    <span class="hljs-keyword">if</span>(hasCameraPermission === <span class="hljs-literal">null</span>){
      <span class="hljs-comment">// requesting permission</span>
      <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Spinner</span> /&gt;</span></span>
      );
    }
    <span class="hljs-keyword">if</span>(hasCameraPermission === <span class="hljs-literal">false</span>){
        <span class="hljs-comment">//permission denied</span>
      <span class="hljs-keyword">return</span> ( 
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Container</span>&gt;</span>
         <span class="hljs-tag">&lt;<span class="hljs-name">TextH3</span>&gt;</span>Please grant Camera permission<span class="hljs-tag">&lt;/<span class="hljs-name">TextH3</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Container</span>&gt;</span></span> 
      )
    }
    <span class="hljs-keyword">if</span>(hasCameraPermission === <span class="hljs-literal">true</span> &amp;&amp; !isScanned &amp;&amp; <span class="hljs-built_in">this</span>.props.navigation.isFocused() ){
      <span class="hljs-comment">// we have permission and this screen is under focus</span>
      <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Container</span> <span class="hljs-attr">style</span> = <span class="hljs-string">{{</span>
        <span class="hljs-attr">flex:</span> <span class="hljs-attr">1</span>,
        <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>',
        <span class="hljs-attr">justifyContent:</span> '<span class="hljs-attr">center</span>',
        <span class="hljs-attr">alignItems:</span> '<span class="hljs-attr">center</span>'

      }}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">TextH3</span>&gt;</span>Scan code inside window<span class="hljs-tag">&lt;/<span class="hljs-name">TextH3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">BarCodeScanner</span>
          <span class="hljs-attr">onBarCodeScanned</span> = <span class="hljs-string">{</span> <span class="hljs-attr">isScanned</span> ? <span class="hljs-attr">undefined</span> <span class="hljs-attr">:</span> <span class="hljs-attr">this.handleBarCodeScanned</span> }
          <span class="hljs-attr">style</span> = <span class="hljs-string">{{</span>
            <span class="hljs-attr">height:</span>  <span class="hljs-attr">window.height</span> / <span class="hljs-attr">2</span>,
            <span class="hljs-attr">width:</span> <span class="hljs-attr">window.height</span>,
          }}
        &gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">BarCodeScanner</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Container</span>&gt;</span></span>
    }
    <span class="hljs-keyword">else</span>{
      <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Spinner</span> /&gt;</span></span>;
    }
  }
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ScannerScreen;
</code></pre>
<p><strong>Github Repo:</strong> <a target="_blank" href="https://github.com/vtechguys/medium/tree/master/RN_bar_code_scanner">vtechguys/medium</a></p>
]]></content:encoded></item></channel></rss>