<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Miroslav Nikolov</title>
    <description>The latest articles on DEV Community by Miroslav Nikolov (@moubi).</description>
    <link>https://dev.to/moubi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F349629%2Fbbe584ff-b363-48be-9e42-3536bfecf50a.jpeg</url>
      <title>DEV Community: Miroslav Nikolov</title>
      <link>https://dev.to/moubi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/moubi"/>
    <language>en</language>
    <item>
      <title>Writing Developer-Friendly React Unit Tests</title>
      <dc:creator>Miroslav Nikolov</dc:creator>
      <pubDate>Tue, 30 Mar 2021 07:09:19 +0000</pubDate>
      <link>https://dev.to/moubi/writing-developer-friendly-react-unit-tests-2pe9</link>
      <guid>https://dev.to/moubi/writing-developer-friendly-react-unit-tests-2pe9</guid>
      <description>&lt;p&gt;You want to write React unit (component) tests in a human-readable manner. In conjunction with the best practices today it should make your life (and the life of your colleague developers) easier and reduce the number of production bugs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should render a button with text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;I am a button&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;when mounted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;to have text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I am a button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This component test is for real. Back on it soon... [🔖]&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Snapshots and direct DOM comparison are &lt;strong&gt;fragile&lt;/strong&gt; while JQuery like chaining syntax &lt;strong&gt;reads bad&lt;/strong&gt; and makes tests wordy. &lt;strong&gt;How to address the readability issue in that case? How to keep up &lt;a href="https://testing-library.com/docs/dom-testing-library/intro#the-problem"&gt;testing components' data flow in isolation&lt;/a&gt; by hiding their implementation details&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Below is my approach to unit testing in React.&lt;/strong&gt; It aims to follow the consensus with a pinch of clarity on top.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  The Component (A Button)
&lt;/h2&gt;

&lt;p&gt;A trivial &lt;a href="https://material-ui.com/components/buttons/"&gt;Material UI-like button&lt;/a&gt; will be used for this demonstration. It is simple enough to unfold the concept with the help of several test examples.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OvoPNjwe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t2e8uc3khz7jz3e2t17o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OvoPNjwe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t2e8uc3khz7jz3e2t17o.png" alt="Material UI-like buttons showcase" width="672" height="57"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Button.js&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;classNames&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Library
&lt;/h2&gt;

&lt;p&gt;Getting back to the test case on top [🔖]. It uses &lt;a href="https://unexpected.js.org/"&gt;UnexpectedJS&lt;/a&gt;—an assertion library compatible with all test frameworks—supplemented by a few plugins to help you working with React components and the DOM.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jest&lt;/strong&gt; is the test runner and behind the scenes, it has &lt;code&gt;react-dom&lt;/code&gt; and &lt;a href="https://reactjs.org/docs/test-utils.html"&gt;react-dom/test-utils&lt;/a&gt; as dependencies.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Testing Setup
&lt;/h3&gt;

&lt;p&gt;There is an &lt;a href="https://github.com/moubi/react-button"&gt;example GitHub repo&lt;/a&gt; you can use as a ref. Head over there for the full picture.&lt;/p&gt;

&lt;p&gt;Otherwise here are some of the more interesting moments:&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  Project Structure
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- src
    |-- components
    |   |-- Button
    |   |   |-- Button.js
    |   |   |-- Button.scss
    |   |   |-- Button.test.js
    |-- test-utils
    |   |-- unexpected-react.js

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  Test Plugins
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;"devDependencies":&lt;/span&gt; {
  ...
&lt;span class="gi"&gt;+ "sinon": "9.2.4",
+ "unexpected": "12.0.0",
+ "unexpected-dom": "5.0.0",
+ "unexpected-reaction": "3.0.0",
+ "unexpected-sinon": "11.0.1"
&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Sinon&lt;/code&gt; is used for spying on functions—callback component props executed as a result of specific user interactions with the UI.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  Test Helper
&lt;/h4&gt;

&lt;p&gt;A test helper named &lt;code&gt;unexpected-react.js&lt;/code&gt; has the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// unexpected-react.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;unexpected&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unexpected&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;unexpectedDom&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unexpected-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;unexpectedReaction&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unexpected-reaction&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;unexpectedSinon&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unexpected-sinon&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;unexpected&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;unexpectedDom&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;unexpectedReaction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;unexpectedSinon&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;simulate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-dom-testing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It simply exports all necessary functions to put together the Button's tests.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Button Component Tests
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Button.test.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;simulate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../test-utils/unexpected-react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;sinon&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sinon&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Test cases&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Individual unit/component tests are placed within a &lt;code&gt;describe()&lt;/code&gt; block. See below.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  1. Render with text.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qS8TMsWL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hjccf6y9g37l9yq55i08.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qS8TMsWL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hjccf6y9g37l9yq55i08.png" alt="A button with text" width="164" height="83"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should render with text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;I am a button&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;when mounted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;to have text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I am a button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Checking if a button renders with the specified text.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  2. Render with custom markup.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Tg7EG_tl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/twurk71swvft2fbs7xgj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Tg7EG_tl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/twurk71swvft2fbs7xgj.png" alt="A button with additional markup" width="168" height="73"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should render with markup&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Download&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;⬇️&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;when mounted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;to satisfy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Download&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;⬇️&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to &lt;strong&gt;compare the DOM structure&lt;/strong&gt;—which in this case may make sense—this is the way to go.&lt;/p&gt;

&lt;p&gt;You can also use &lt;code&gt;data-test-id&lt;/code&gt; with its relevant assertion. Fx.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should render with markup&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;i&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;data-test-id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button-text"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Download
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;when mounted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;queried for test id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;to have text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Download&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  3. Render a primary button.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tsDg0QaX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t8r357s4oddinoift0bh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tsDg0QaX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t8r357s4oddinoift0bh.png" alt="Primary button" width="127" height="79"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should render as primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"primary"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Primary&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;when mounted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;to have class&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two supported &lt;code&gt;color&lt;/code&gt; prop values: primary and secondary. These are then set as CSS classes.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  4. Render a small button.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--d194Fqn1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r3t4xib454q2tqyn5p29.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--d194Fqn1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r3t4xib454q2tqyn5p29.png" alt="Small button" width="99" height="70"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should render as small&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"small"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Small&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;when mounted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;to have class&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;small&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similar to &lt;code&gt;color&lt;/code&gt; there are two values for the &lt;code&gt;size&lt;/code&gt; prop: small and large.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  5. Render as disabled.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--U_qMo_Ty--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4n3oiav79rj6vg81pn3u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--U_qMo_Ty--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4n3oiav79rj6vg81pn3u.png" alt="Disabled button" width="135" height="81"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should render as disabled&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Disabled&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;when mounted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;to have attributes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Checking for the &lt;code&gt;disabled&lt;/code&gt; attribute. That's all.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  6. Don't trigger click handlers.
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should NOT trigger click if disabled&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sinon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stub&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Press&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;simulate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;was not called&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;onClick&lt;/code&gt; callback should not be executed on disabled-buttons.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  7. Handle a click.
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should trigger click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sinon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stub&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Click here&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;simulate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;was called&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;was called&lt;/code&gt; assertion here has a better alternative if you need to test for arguments passed to the handler. Fx.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Passing a checkbox state (checked) to the callback&lt;/span&gt;
&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;to have a call satisfying&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  8. Tests output.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xPhiHMdb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uebdppufx0sq7xyw3wsz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xPhiHMdb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uebdppufx0sq7xyw3wsz.png" alt="Jest terminal output" width="371" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is what you will see in the terminal if all unit tests are passing.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Final Words
&lt;/h2&gt;

&lt;p&gt;There is a trend for testing in React (and testing in general) which has been started by React Testing Library and seems &lt;a href="https://www.reddit.com/r/reactjs/comments/lnapvh/the_current_state_of_hoc_hooks_and_render_props/go0yqpp?utm_source=share&amp;amp;utm_medium=web2x&amp;amp;context=3"&gt;the majority of our community is going after it&lt;/a&gt;. Its guiding principle is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;...you want your tests to avoid including implementation details of your components and rather focus on making your tests give you the confidence for which they are intended.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This statement translates to something like &lt;em&gt;&lt;strong&gt;"you should not test against components' DOM structure but rather focus on data flow."&lt;/strong&gt;&lt;/em&gt; Changes in your component DOM should not break your tests.&lt;/p&gt;

&lt;p&gt;UnexpectedJS comply with this principle by allowing you to easily test for &lt;code&gt;data-test-id&lt;/code&gt; (or &lt;code&gt;aria-*&lt;/code&gt; attributes) while at the same time encourages writing human-readable unit tests by its custom assertions.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;PS: Would such an approach be of a value to you?&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Join My Programming Newsletter
&lt;/h2&gt;

&lt;p&gt;I send it out once a month. It contains my latest write-up plus useful links and thoughts on topics I can't easily find answers by just Googling.&lt;/p&gt;

&lt;p&gt;If it sounds interesting &lt;a href="https://webup.org/blog/subscribe/"&gt;head over and add your email&lt;/a&gt;.&lt;br&gt;
&lt;em&gt;Spam-free.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>testing</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What Is Your Aha Moment With React</title>
      <dc:creator>Miroslav Nikolov</dc:creator>
      <pubDate>Wed, 24 Mar 2021 16:39:06 +0000</pubDate>
      <link>https://dev.to/moubi/what-is-your-aha-moment-with-react-e1k</link>
      <guid>https://dev.to/moubi/what-is-your-aha-moment-with-react-e1k</guid>
      <description>&lt;p&gt;My early days with React were... difficult. &lt;/p&gt;

&lt;p&gt;Things didn't go straight. So many bumps and new concepts. It was slow to grasp Redux, rendering and class components.&lt;/p&gt;

&lt;p&gt;Partly because I was so used to OOP in JavaScript, partly due to the new component UI patterns, I have to admit the whole journey was full of surprises and not easy. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;Hooks&lt;/code&gt; didn't make things easier, either.&lt;/p&gt;

&lt;p&gt;🙀 &lt;strong&gt;What is your latest React Aha moment?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Evergreen CSS Flex Layouts With Live Demos</title>
      <dc:creator>Miroslav Nikolov</dc:creator>
      <pubDate>Wed, 10 Mar 2021 12:05:02 +0000</pubDate>
      <link>https://dev.to/moubi/evergreen-css-flex-layouts-with-live-demos-mnm</link>
      <guid>https://dev.to/moubi/evergreen-css-flex-layouts-with-live-demos-mnm</guid>
      <description>&lt;p&gt;I have to deal with CSS Flex layouts very often but noticed building them from scratch every time. That's irritating. &lt;/p&gt;

&lt;p&gt;So I put together a growing list of &lt;a href="https://webup.org/blog/evergreen-css-flex-layouts-with-demos/"&gt;9 demos with copy-paste ready code snippets&lt;/a&gt; to help me start with a proper base next time.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Head to the previews and tell me what is the template you are missing there.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>discuss</category>
      <category>showdev</category>
      <category>css</category>
    </item>
    <item>
      <title>React HoC vs Hooks vs Render Props in 2021</title>
      <dc:creator>Miroslav Nikolov</dc:creator>
      <pubDate>Tue, 23 Feb 2021 06:48:03 +0000</pubDate>
      <link>https://dev.to/moubi/the-current-state-of-react-hocs-hooks-and-render-props-5ae4</link>
      <guid>https://dev.to/moubi/the-current-state-of-react-hocs-hooks-and-render-props-5ae4</guid>
      <description>&lt;p&gt;Did React hooks took over or there is still room for the HoC and render prop patterns?&lt;/p&gt;




&lt;p&gt;In 2021 React hooks are everywhere and many serious OSS projects are using functional components already.&lt;/p&gt;

&lt;p&gt;During ReactEurope &lt;a href="https://twitter.com/erikras"&gt;Erik Rasmussen&lt;/a&gt; did a good round-up of how things started with &lt;strong&gt;HoCs&lt;/strong&gt;, went through their replacement — &lt;strong&gt;render props&lt;/strong&gt; — and ended up today with &lt;strong&gt;hooks&lt;/strong&gt;. It also compares several use cases.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/pn0pIgdQvhU"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If I have to make my own conclusion it would sound like that:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;HoC, hooks and render props have their own use cases and none of them is a full replacement of the others. In some cases HoCs and components with a render prop my even make more sense.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A good example of the above is the &lt;a href="https://react-redux.js.org/api/connect"&gt;connect()&lt;/a&gt; function from React Redux used to connect your component to the store. It does return a HoC.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This will return a HoC wrapper around MyComponent&lt;/span&gt;
&lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="nx"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the modern Redux you can get data and dispatch actions to the store directly using the &lt;code&gt;useSelector&lt;/code&gt; and &lt;code&gt;useDispatch&lt;/code&gt; hooks, so &lt;code&gt;connect()&lt;/code&gt; is no longer required. &lt;strong&gt;While it's true, this is one of these moments where I find the HoC pattern still useful for production apps&lt;/strong&gt;. The main reason is... testing. It's very easy to test a component in isolation via props.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;// own prop&lt;/span&gt;
  &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;// own prop&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;// redux store selector&lt;/span&gt;
  &lt;span class="nx"&gt;activateAction&lt;/span&gt;  &lt;span class="c1"&gt;// redux action&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the hooks your tests won't be that straightforward as &lt;a href="https://blog.isquaredsoftware.com/2019/07/blogged-answers-thoughts-on-hooks/"&gt;per some tradeoffs&lt;/a&gt; but this is the recommended way to go in the React community.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To wrap up:&lt;/strong&gt; Functional components and react hooks are our preferred way of working with React these days but &lt;a href="https://webup.org/blog/render-props-vs-hooks"&gt;hooks are not always your silver bullet&lt;/a&gt;. Collaboration, testing, reusability, and logic explicitness, should determine what is a better fit and not the mainstream.&lt;/p&gt;




</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>codequality</category>
    </item>
    <item>
      <title>React Patterns: A Component with Many Content Variants</title>
      <dc:creator>Miroslav Nikolov</dc:creator>
      <pubDate>Tue, 09 Feb 2021 07:56:03 +0000</pubDate>
      <link>https://dev.to/moubi/handle-a-component-with-unknown-content-variants-b38</link>
      <guid>https://dev.to/moubi/handle-a-component-with-unknown-content-variants-b38</guid>
      <description>&lt;p&gt;A dumb component renders any text passed while its visual appearance remains static. It is also unknown how many new content variations are about to come. What would be a useful React pattern in this scenario?&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Look at the right side of the picture below.&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frsih26v5pogyrkociiy7.png" class="article-body-image-wrapper"&gt;&lt;img alt="Dumb and Smart React components" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frsih26v5pogyrkociiy7.png"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;It displays two lines of text and a link. You will face no issues representing it with a single component until the content becomes dynamic and &lt;strong&gt;texts/link need to change&lt;/strong&gt;. In such case &lt;strong&gt;presentation (aka design) is the same&lt;/strong&gt;, but content may have &lt;strong&gt;fluid variations&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The challenge is to organize your code, so it remains simple and allows for painless future changes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are three things to take care of along the way: styling, data, and business logic.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;It aims for &lt;em&gt;flexibility&lt;/em&gt; and &lt;em&gt;maintainability&lt;/em&gt;. Making future changes should be straightforward as that is the real pain point here — prepare the code for &lt;a href="https://webup.org/blog/the-emerging-ship#incomplete-requirements" rel="noopener noreferrer"&gt;hidden information causing new uses cases&lt;/a&gt; to pop in.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Folder Structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;
   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;Box&lt;/span&gt;
       &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;
       &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;
       &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;
           &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;Text1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;
           &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;Text2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;
           &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;Text3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;
           &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;Text4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The solution involves two-component levels — parent component (&lt;code&gt;&amp;lt;Box /&amp;gt;&lt;/code&gt;) and several child components for each textual case (&lt;code&gt;&amp;lt;TextN /&amp;gt;&lt;/code&gt;). Note that child component names above are chosen to simplify the picture. Ideally, you should name them after each specific use case, fx. &lt;code&gt;StorageEmptyText.js&lt;/code&gt;, &lt;code&gt;StorageAboveAverageText.js&lt;/code&gt;, &lt;code&gt;StorageFullText.js&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Box Component
&lt;/h3&gt;

&lt;p&gt;That's the parent (container) component. Its purpose is to manage business logic and styling.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Box.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;StorageEmptyText&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components/StorageEmptyText&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;StorageAboveAverageText&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components/StorageAboveAverageText&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;StorageFullText&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components/StorageFullText&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;openDialogAction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;manageStorageAction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;upgradeToProPlanAction&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;TextComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// 1️⃣ Use case logic: conditionally assign text component and click action&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;TextComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;StorageEmptyText&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;openDialogAction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;TextComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;StorageAboveAverageText&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;manageStorageAction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;TextComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;StorageFullText&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;upgradeToProPlanAction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// 2️⃣ More cases to follow&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Box"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* 3️⃣ A component with render prop is famous for its flexibility */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TextComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* 4️⃣ Box.js (the parent) holds these elements' styling */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;TextComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Several benefits emerge from such a structure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The markup around each text is part of &lt;code&gt;Box.js&lt;/code&gt; so you can style it here.&lt;/li&gt;
&lt;li&gt;The use case logic is explicit.&lt;/li&gt;
&lt;li&gt;Child components are nearby.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Having texts encapsulated in &lt;code&gt;&amp;lt;TextComponent /&amp;gt;&lt;/code&gt;s instead of a function or hooks will also lighten the tests. You will need to check the &lt;code&gt;className&lt;/code&gt; or &lt;code&gt;data-test-id&lt;/code&gt; presence for each use case, not the actual texts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Box.test.js&lt;/span&gt;

&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt; &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;95&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;when mounted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;to contain elements matching&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.StorageFullText&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Text Components
&lt;/h3&gt;

&lt;p&gt;You may have any number of these components. They share the same structure — dumb component with a &lt;a href="https://reactjs.org/docs/render-props.html#gatsby-focus-wrapper" rel="noopener noreferrer"&gt;render prop function&lt;/a&gt; to accept the texts. File names should be descriptive as that gives you a hint of what's going on by both, looking at the folder structure and maintaining the logic in &lt;code&gt;Box.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// StorageFullText.js&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;StorageFullText&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"StorageFullText"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/*
        Passes down its texts to a children() function
        That allows for custom styling in the parent
      */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;children&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Looks like you have too many items&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Upgrade to our Pro plan or free up more space in your box.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;See all plans&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;&amp;lt;StorageFullText /&amp;gt;&lt;/code&gt; uses render prop to send back data and is not aware of how texts are consumed later on. One of the reasons for using this pattern is the &lt;a href="https://webup.org/blog/render-props-vs-hooks/#re-render-only-what-is-relevant" rel="noopener noreferrer"&gt;flexibility render prop components provide over hooks&lt;/a&gt; fx.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Final Words
&lt;/h2&gt;

&lt;p&gt;Handling text components may look simple on the surface, but in some situations requires you to take a different approach and the extra step.&lt;/p&gt;

&lt;p&gt;If a component doesn't change its visual representation and structure but may have many content variants, it makes sense to involve fewer wrappers if possible. The guiding principle is to avoid being smart about code reusability. Instead, go &lt;strong&gt;explicit and minimal&lt;/strong&gt; expecting things to change.&lt;/p&gt;




&lt;h1&gt;
  
  
  📩
&lt;/h1&gt;

&lt;p&gt;I maintain a &lt;a href="https://webup.org/blog/subscribe/" rel="noopener noreferrer"&gt;monthly blog newsletter&lt;/a&gt; with more posts like this.&lt;/p&gt;




</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>codequality</category>
    </item>
    <item>
      <title>How Can Developers Save a Failing Project</title>
      <dc:creator>Miroslav Nikolov</dc:creator>
      <pubDate>Mon, 18 Jan 2021 07:22:33 +0000</pubDate>
      <link>https://dev.to/moubi/how-can-developers-save-a-failing-project-558j</link>
      <guid>https://dev.to/moubi/how-can-developers-save-a-failing-project-558j</guid>
      <description>&lt;p&gt;&lt;strong&gt;Quick summary:&lt;/strong&gt; A project is about to fail. Everybody feels it won't meet the hard deadline. But the app ended up released on time and bug-free. How is that possible?&lt;/p&gt;

&lt;p&gt;I want to tell you the real story behind &lt;strong&gt;an ambitious two-month project&lt;/strong&gt; my team completed, with a huge impact on our organization. A very stressful, challenging, and full of surprises journey, marked by developers being the leaders. &lt;strong&gt;I intend to reveal why things went bad and how with a proper smart set of decisions the front-end team managed to navigate its boat&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Table of Contents
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
The Project

&lt;ul&gt;
&lt;li&gt;Project Context&lt;/li&gt;
&lt;li&gt;Project Goal&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;What Compromised the Project (Early Signs)&lt;/li&gt;
&lt;li&gt;Developers in Charge&lt;/li&gt;
&lt;li&gt;
Developers' Strategy to Deal with Impediments

&lt;ul&gt;
&lt;li&gt;No Clear Leadership&lt;/li&gt;
&lt;li&gt;Lack of Domain Knowledge&lt;/li&gt;
&lt;li&gt;Incomplete Requirements&lt;/li&gt;
&lt;li&gt;Too Many Teams&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Best Practices Summary&lt;/li&gt;
&lt;li&gt;Final Words&lt;/li&gt;
&lt;li&gt;Resources&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Project
&lt;/h2&gt;

&lt;p&gt;The project is intentionally interpreted mostly from a front-end perspective to avoid the risk of having a blurry presentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which parties were involved:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Product owner (PO)&lt;/li&gt;
&lt;li&gt;Front-end team (2 devs)&lt;/li&gt;
&lt;li&gt;Backend team (2 devs)&lt;/li&gt;
&lt;li&gt;QA team (2 testers)&lt;/li&gt;
&lt;li&gt;UX/Designer&lt;/li&gt;
&lt;li&gt;Content manager (translations)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In total &lt;strong&gt;9 people&lt;/strong&gt; from &lt;strong&gt;6 departments&lt;/strong&gt; were allocated for this two-month effort (around 9 weeks). The UX design was done in advance, so it's not included in the total duration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Context
&lt;/h3&gt;

&lt;p&gt;Rapidly growing companies are usually investing in new hires and changes in the hierarchy structure. From all the &lt;strong&gt;9 people involved&lt;/strong&gt;, 2 were &lt;strong&gt;new employees&lt;/strong&gt; (PO and design), 2 had &lt;strong&gt;a year of experience&lt;/strong&gt; in the organization, and from all &lt;strong&gt;6 teams&lt;/strong&gt; 3 were &lt;strong&gt;newly formed&lt;/strong&gt; while the rest were &lt;strong&gt;restructured&lt;/strong&gt; to an extent. The &lt;strong&gt;newly formed&lt;/strong&gt; UX team was extensively focused on the UIs in Figma  backed with translations delivered by a content manager who &lt;strong&gt;switched departments&lt;/strong&gt;. On top of that building applications with a PO was &lt;strong&gt;new for us&lt;/strong&gt; - these duties used to be fulfilled by a project manager in the past.&lt;/p&gt;

&lt;p&gt;Where was I in the whole picture? You probably know the answer. Yes, I was too part of a &lt;strong&gt;newly formed web apps team&lt;/strong&gt; of front-end developers. Up until this moment we were located in different cross-functional teams formed around specific long-term company products.&lt;/p&gt;

&lt;p&gt;So many new, new, new.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To summarize:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Dynamic environment, new colleagues, new company structure. A  dangerous combination for ambitious projects with tight deadlines.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Project Goal
&lt;/h3&gt;

&lt;p&gt;The purpose of the application was to allow customers &lt;strong&gt;easily find and operate&lt;/strong&gt; on their subscription data, &lt;strong&gt;reducing, as a side effect, the number of related support tickets&lt;/strong&gt; significantly.&lt;/p&gt;

&lt;p&gt;To make things more complicated the project must account for all services, add-on products, and user edge cases dragged in over the years of product development.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Compromised the Project (Early Signs)
&lt;/h2&gt;

&lt;p&gt;Getting back from vacation I was immediately thrown into the process, having no idea what this new project is about. All planning and grooming sessions were already in the past, and teams were formed. At the same time, it was left to the individual parties to self-organize somehow and find their way in. I felt very uncomfortable and anxious: no information to start with, no initial setup, but probably the &lt;strong&gt;the most noticeable fact was the lack of clear leadership&lt;/strong&gt;. To fill the gap &lt;strong&gt;many project management tasks got "naturally" assigned to the front-end team&lt;/strong&gt; and from that point on required additional time for coordination.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A quick side note:&lt;/strong&gt; Often a project failure is determined by a few common factors. In one of his recent &lt;a href="https://mailinglist.humanwhocodes.com/" rel="noopener noreferrer"&gt;newsletters&lt;/a&gt; (&lt;em&gt;"Thoughts on mistakes"&lt;/em&gt;) &lt;a href="https://twitter.com/slicknet" rel="noopener noreferrer"&gt;Nicholas Zakas&lt;/a&gt; grouped them like so: &lt;strong&gt;skills, luck&lt;/strong&gt;, and &lt;strong&gt;hidden information&lt;/strong&gt;. In such a combination they influence the outcome of a decision, but all of them apply to IT projects in general.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;With a few exceptions, you can control the amount of skill you bring into making a decision, and you can work to uncover hidden information (though sometimes it's not obvious where to look), but luck is completely out of your control.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Getting back to the story, and I have to admit, it was a &lt;strong&gt;minefield of hidden information&lt;/strong&gt; popping up until the final release. All the skills required were present and even more of that. No unexpected event, call it luck if you want, has ever occurred. To uncover and deal with invisible use cases or wrong assumptions was the project's most common bottleneck.&lt;/p&gt;

&lt;p&gt;What prompted hidden information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No clear leadership.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not having a dedicated PM or a fully available project lead resulted in recurring distractions to handle organizational activities.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lack of domain knowledge.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not understanding the domain well enough — especially by new employees — is interconnected with the number of changes coming later in the development process. The higher the position, the worse.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Incomplete requirements.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gaps in domain knowledge led to unclear or too narrow requirements driven by not actively involving people with good matter understanding in the planning stage.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Too many teams.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having to coordinate six different teams would be a needless effort if people were otherwise grouped around the project in a single cross-functional unit.&lt;/p&gt;

&lt;p&gt;All these implications didn't give us up, of course, but &lt;strong&gt;forced (the front-end devs at least) to deliberately address problematic areas both code and management-wise&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But why should developers share the organizational burden, you may ask? Couldn't you simply pass it down to the PO or someone from the upper management? After all, it is their job and you are just writing code, right? These are legit questions and we asked them ourselves many times, nevertheless the project ended up deliberately led by the dev team. &lt;strong&gt;We were developers in charge.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Developers in Charge
&lt;/h2&gt;

&lt;p&gt;The IT practice confirms whenever a team finds itself in a project storm, the best strategy is to &lt;strong&gt;allow experience developers to navigate the ship&lt;/strong&gt;. This should go on until the process can be run in a normal temp with planning phases and iterations — in other words when the storm has already passed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Extreme Programming (XP) was created in response to problem domains whose requirements change. Your customers may not have a firm idea of what the system should do. You may have a system whose functionality is expected to change every few months. In many software environments dynamically changing requirements is the only constant. This is when XP will succeed while other methodologies do not.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The quote from &lt;a href="http://www.extremeprogramming.org/when.html" rel="noopener noreferrer"&gt;when should XP be used&lt;/a&gt; well describes the situation I was in at that moment. Our tech fellowship took the lead, because: &lt;strong&gt;we knew QA and backend devs well understand the domain, our front-end team can provide fast feedback loops, we are closer to the UI and flexible enough to allow for late changes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It was the right move.&lt;/strong&gt; Situations like this should be considered extraordinary and avoided whenever possible, though. There is nothing better than working in a constant phase, doing what you do best, while PM handles the cross-team links. Everybody is on their seats and no huge surprises are to be expected. By saying this I also understand it's largely wishful thinking. The harsh truth is &lt;strong&gt;most of the companies are not agile&lt;/strong&gt; or don't follow any structured methodology or apply frameworks like SCRUM or Kanban. I am a Kanban fan, but even &lt;a href="https://medium.com/better-programming/scrum-is-dead-all-hail-kanban-the-new-king-2cd6249feef8" rel="noopener noreferrer"&gt;its obvious benefits&lt;/a&gt; are rarely enough to convince organizations to give it a try nowadays. Despite the endless sugary talks and big investments in agile frameworks like SCRUM fx., &lt;strong&gt;most of the companies rely on XP&lt;/strong&gt; even if they don't realize it. Developers' responsibilities overlap with PM, marketing, SEO, design, etc., and that is not a coincidence.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiooc6z7imfs4dohwf9jb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiooc6z7imfs4dohwf9jb.png" alt="Take some rest"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Developers' Strategy to Deal with Impediments
&lt;/h2&gt;

&lt;p&gt;We, in the front-end, built a flexible strategy to deal with project uncertainty, quickly realizing that great code alone won't be enough for our success.&lt;/p&gt;

&lt;p&gt;My colleagues are skilled people who rarely face technical challenges they can't solve, while sporadic events (like the Covid-19 crisis) are very much unpredictable and difficult to prepare for. With this in mind, the strategy's focus is put primarily on &lt;strong&gt;dealing with hidden information and minimizing its negative impact project-wise&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Once more, the four impediments:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No clear leadership.&lt;/li&gt;
&lt;li&gt;Lack of domain knowledge.&lt;/li&gt;
&lt;li&gt;Incomplete requirements.&lt;/li&gt;
&lt;li&gt;Too many teams.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Solving each problem will eventually catalyze more data discoveries throughout the process, providing you, alongside, with handy tools to handle incoming change requests.&lt;/p&gt;

&lt;p&gt;Let's take a closer look.&lt;/p&gt;

&lt;h3&gt;
  
  
  No Clear Leadership
&lt;/h3&gt;

&lt;p&gt;I decided to act proactively on this sudden project and conducted a &lt;strong&gt;kick-off meeting&lt;/strong&gt; to organize everybody and build-up some confidence. The agenda was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Project requirements&lt;/li&gt;
&lt;li&gt;Duties between teams&lt;/li&gt;
&lt;li&gt;Front-end tasks&lt;/li&gt;
&lt;li&gt;Project repo and codebase&lt;/li&gt;
&lt;li&gt;Communication channels&lt;/li&gt;
&lt;li&gt;Split and estimation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This was an opportunity to meet for the first time and get a feeling the project is finally moving. Further on &lt;strong&gt;regular sync meetings&lt;/strong&gt; were set to discuss blockers, progress, or new information collected previously.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lack of Domain Knowledge
&lt;/h3&gt;

&lt;p&gt;It became obvious the QA and backend teams best understand most of the underlying use cases. Two activities helped in this situation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quick short iterations and early releases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Deployments were performed daily so that QA and backend always had something usable to exercise on.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frequent sync meetings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the place to discuss any new findings since the last release and to turn them into development tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Incomplete Requirements
&lt;/h3&gt;

&lt;p&gt;Incomplete requirements are often "dressed" in a "final" UI design and are usually captured late when QA puts their hands on the front-end prototype. The following recipe was used to answer back:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deploy incomplete prototypes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Releasing usable prototypes with fake backend and English texts to allow for a quick feedback loop is a good idea as often endpoints may not yet exist, translations and production-ready texts may also be in progress.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Break the &lt;a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself" rel="noopener noreferrer"&gt;DRY principle&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The DRY principle is of no use when working with frequently changing prerequisites where a &lt;a href="https://overreacted.io/the-wet-codebase/" rel="noopener noreferrer"&gt;WET codebase&lt;/a&gt; will enable quick interventions with almost no side effects.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accompany every change with refactoring.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Frequent changes often introduce tech debt. Writing explicit code and conveying each tweak with a small refactoring in the same place/component is one way to deal with it. This investment pays off with every subsequent change.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Test it thoroughly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep high testing standards no matter what. They guarantee bug-free releases. Writing tests for every new feature or an edge case is important because it also leverages our confidence level in the chaos of thousands of new additions and deletions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Too Many Teams
&lt;/h3&gt;

&lt;p&gt;One of the worst combinations is an actively coding programmer who at the same time is required to manage a project. It is &lt;strong&gt;something to be avoided in any means or, if not possible, used very wisely for a short period&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;How did the front-end team compensate for the coordination cost:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Passing duties between each other.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I and my colleague shared the burden by having shifts when organizing sync meetings and handling iteration loops.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set direct communication channels.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That was done in Slack for everything from status updates, through requirements discussions, to meetings planning.&lt;/p&gt;




&lt;h2&gt;
  
  
  Best Practices Summary
&lt;/h2&gt;

&lt;p&gt;The table below summarizes the practical principles to deal with certain project bottlenecks:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Benefits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hold a kick-off meeting&lt;/td&gt;
&lt;td&gt;Builds confidence and reduces stress.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hold regular sync meetings&lt;/td&gt;
&lt;td&gt;Polishes requirements by giving a chance to parties with domain knowledge to share.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Keep iterations short&lt;/td&gt;
&lt;td&gt;Quick feedback and testing ideas.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Release a static prototype early&lt;/td&gt;
&lt;td&gt;Potentially catching major assumption flaws ahead of time.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use WET vs DRY principle&lt;/td&gt;
&lt;td&gt;Painless and frequent changes with minor side effects.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Make changes in conjunction with refactoring&lt;/td&gt;
&lt;td&gt;High codebase quality and quicker future changes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test the edge cases&lt;/td&gt;
&lt;td&gt;Minimizes code fragility over time. High chances of releasing bug-free products.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Share management duties&lt;/td&gt;
&lt;td&gt;Reduces multitasking and allows for focus on technological challenges.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Final Words
&lt;/h2&gt;

&lt;p&gt;I have to admit that I didn't work overtime for this project. That creates a false feeling of success which in turn tricks you to repeat the same mistakes next time.&lt;/p&gt;

&lt;p&gt;Surprising results were achieved by applying the strategy above and I would like to bring some numbers. The project itself was not lengthy (9 weeks), but appeared to be heavy in terms of tasks and iterations completed. Launched &lt;strong&gt;within its hard deadline&lt;/strong&gt; we had &lt;strong&gt;zero bugs reported on the front-end&lt;/strong&gt; two months after its release - I basically hit the deploy button and moved on. Simultaneously our work had a great effect support-wise with around &lt;strong&gt;250 fewer domain-related tickets per week&lt;/strong&gt; reported.&lt;/p&gt;

&lt;p&gt;What had happened comes to confirm&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;XP projects unanimously report greater programmer productivity when compared to other projects within the same corporate environment.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Remember this little guide if your next project gets in peril.&lt;/p&gt;

&lt;h1&gt;
  
  
  📩
&lt;/h1&gt;

&lt;p&gt;If you face process or code challenges Google Search can't help you with, &lt;a href="https://webup.org/blog/subscribe/" rel="noopener noreferrer"&gt;join my readers group&lt;/a&gt;. I send monthly updates with posts like this.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;"Thoughts on mistakes" - a "Top of the Month newsletter" issue by &lt;a href="https://twitter.com/slicknet" rel="noopener noreferrer"&gt;Nicholas Zakas&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.extremeprogramming.org/when.html" rel="noopener noreferrer"&gt;When should Extreme
Programming be Used?&lt;/a&gt; - requirements for XP's implementation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/better-programming/scrum-is-dead-all-hail-kanban-the-new-king-2cd6249feef8" rel="noopener noreferrer"&gt;Scrum Is Dead. All Hail Kanban, the New King&lt;/a&gt; - some of the benefits of Kanban over SCRUM from a practical perspective&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself" rel="noopener noreferrer"&gt;Don't repeat yourself&lt;/a&gt; - what does DRY mean (Wikipedia)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://overreacted.io/the-wet-codebase/" rel="noopener noreferrer"&gt;The WET Codebase&lt;/a&gt; - a video by Dan Abramov on why WET approach is often better for code collaboration.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Sticky Table Header with React Hooks</title>
      <dc:creator>Miroslav Nikolov</dc:creator>
      <pubDate>Wed, 02 Dec 2020 08:11:55 +0000</pubDate>
      <link>https://dev.to/moubi/sticky-table-header-with-react-hooks-59f7</link>
      <guid>https://dev.to/moubi/sticky-table-header-with-react-hooks-59f7</guid>
      <description>&lt;p&gt;&lt;strong&gt;Using a &lt;code&gt;&amp;lt;table /&amp;gt;&lt;/code&gt; element instead of flexbox for data presentation is a good thing. How to turn the table header sticky with the help of React in that case? How to apply the solution into a production code?&lt;/strong&gt; This blog post is all about that.&lt;/p&gt;

&lt;p&gt;What follows is not a trivial tutorial on how you should solve the task. It is not a theory or fictional implementation, either. Instead, the focus is around a possible solution tested in real projects that you can easily reuse. It also sorts out some of the edge cases when working with &lt;code&gt;&amp;lt;table /&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Go straight to the code, if that's mostly what your are looking for.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Table of Contents:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Tables vs Flexbox&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Control Columns via Header Cells&lt;/li&gt;
&lt;li&gt;Header and Content Component Split&lt;/li&gt;
&lt;li&gt;Tables Work Out of the Box&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sticky Header (code solution)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;lt;Table /&amp;gt; Component Interface&lt;/li&gt;
&lt;li&gt;&amp;lt;Table /&amp;gt; Component Implementation&lt;/li&gt;
&lt;li&gt;useStickyHeader() Implementation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Final Words&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Resources&lt;/p&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Tables vs Flexbox
&lt;/h2&gt;

&lt;p&gt;Whenever you have to deal with data presentation, often the first intention is to create a &lt;code&gt;&amp;lt;div /&amp;gt;&lt;/code&gt; based layout with flexbox. People are somehow biased to tables. Tables have a bad reputation of being used for building web pages in the past. &lt;strong&gt;But if done right, they can save you a ton of problems. Tables do also play very well with React.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On the other side, it doesn't come very handy to loop over your data and place it in a flexbox based grid.&lt;/strong&gt; A good illustration on the problem is described in &lt;a href="https://css-tricks.com/accessible-simple-responsive-tables/#1b-for-column-oriented-tables" rel="noopener noreferrer"&gt;Accessible, Simple, Responsive Tables&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0962ocm86yatcr0rlvqi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0962ocm86yatcr0rlvqi.png" alt="Flexbox based table layout"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;
&lt;sup&gt;Table layout with flexbox. The screenshot is taken from &lt;a href="https://codepen.io/moubi/pen/WNxVdxY" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;sup&gt;
&lt;/sup&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;The table-like layout above is styled with flex and looks very similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"table"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h3&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Eddard Stark&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Has a sword named Ice&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;No direwolf&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Lord of Winterfell&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;h3&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Jon Snow&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Has a sword named Longclaw&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Direwolf: Ghost&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Knows nothing&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  ...
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A question quickly arises: How easy would be to iterate over the headers and rows data with the given markup?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contrary, some of the table benefits include:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Column width control via header cells&lt;/li&gt;
&lt;li&gt;Painless component-wise split between header and content (table rows)&lt;/li&gt;
&lt;li&gt;Works out of the box (no css)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All these are closely related to the challenges behind turning table headers (&lt;code&gt;&amp;lt;thead /&amp;gt;&lt;/code&gt;) into sticky items. Understanding them, should help you better follow the code solution after.&lt;/p&gt;




&lt;p&gt;You can build table layouts by using the usual &lt;code&gt;&amp;lt;table /&amp;gt;&lt;/code&gt; tag or achieve the same via css with &lt;code&gt;display: table&lt;/code&gt; and semantic elements (&lt;code&gt;&amp;lt;div /&amp;gt;&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;thead&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  ...
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;// is the same as&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;table&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;table-header-group&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  ...
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same visual result. The first one, though, will cause React to complain (also in tests) if you place &lt;code&gt;&amp;lt;thead /&amp;gt;&lt;/code&gt; outside its &lt;code&gt;&amp;lt;table /&amp;gt;&lt;/code&gt; parent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;thead&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- Warning: validateDOMNesting(...): &amp;lt;thead&amp;gt; cannot appear as a child of &amp;lt;div&amp;gt;.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the sake of simplicity and to be more explicit, all examples that come after are based on the &lt;code&gt;&amp;lt;table /&amp;gt;&lt;/code&gt; element.&lt;/p&gt;

&lt;p&gt;Back on the benefits.&lt;/p&gt;

&lt;h3&gt;
  
  
  Control Columns via Header Cells
&lt;/h3&gt;

&lt;p&gt;It may appear counterintuitive since the header and body cells are placed far from each other in the DOM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;table&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;thead&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width: 200px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Header cell&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/thead&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;Table cell 1&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;Table cell 2&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example the width of all &lt;code&gt;&amp;lt;td /&amp;gt;&lt;/code&gt; elements will be the same as the width set with &lt;code&gt;&amp;lt;th style="width: 200px;"&amp;gt;Header cell&amp;lt;/th&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You get a side effect that allows for easy control over columns size with no additional cost of setting extensive css rules.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Header and Content Component Split
&lt;/h3&gt;

&lt;p&gt;Apart from column sizing, sorting and filtering features are too mostly attached to the headers. It turns out they are very powerful unit for ruling the whole table. Such dependencies pop in especially whenever you need to split the table into React components.&lt;/p&gt;

&lt;p&gt;Look into this Table component interface (without getting into details):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt; &lt;span class="na"&gt;sortable&lt;/span&gt; &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Country&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Population&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dataAfterSorting&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;dataAfterSorting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TableDataRow&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://reactjs.org/docs/fragments.html#motivation" rel="noopener noreferrer"&gt;This structure comes natural&lt;/a&gt; because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;It follows how tables render in the DOM (&lt;em&gt;with separate header and body sections&lt;/em&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sorting functionality is attached to the header.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Headers set their own styles. That includes sorting indicators, hover states, but behavior (click handlers) too. A separate component that orchestrates the whole content being decoupled from it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The content is not aware of its context.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Components like &lt;code&gt;&amp;lt;TableDataRow /&amp;gt;&lt;/code&gt; may live outside the table. It accepts a slice of a pre-sorted data and simply renders a row with its own styling. &lt;strong&gt;This component is not aware of its context and doesn't need to. With one exception: the amount of cells (&lt;code&gt;&amp;lt;td /&amp;gt;&lt;/code&gt;) it displays must be the same as in the header.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tables Work Out of the Box
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://css-tricks.com/complete-guide-table-element/" rel="noopener noreferrer"&gt;Tables are straightforward and well known&lt;/a&gt;. You don't need additional code to achieve a basic presentation for a given data set. By simply using the &lt;code&gt;&amp;lt;table /&amp;gt;&lt;/code&gt; structure you already have a form for the numbers.&lt;/p&gt;

&lt;p&gt;The same is not true for &lt;strong&gt;flexbox&lt;/strong&gt; as discussed earlier.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sticky Header (code solution)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmq743fjx4qh6p4a6lqfg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmq743fjx4qh6p4a6lqfg.gif" alt="Comparison between render props and custom hook form"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the demo implementation and its code can be found in the &lt;a href="https://codesandbox.io/s/sticky-header-table-with-react-3j5zy?file=/src/Table.js" rel="noopener noreferrer"&gt;CodeSandbox project&lt;/a&gt;. The stickiness is achieved by a simple &lt;code&gt;&amp;lt;Table /&amp;gt;&lt;/code&gt; component and a &lt;code&gt;useStickyHeader&lt;/code&gt; React hook.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reuse it by adding your custom table styles in &lt;a href="https://codesandbox.io/s/sticky-header-table-with-react-3j5zy?file=/src/styles.css" rel="noopener noreferrer"&gt;styles.css&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &amp;lt;Table /&amp;gt; Component Interface
&lt;/h3&gt;

&lt;p&gt;The Table component itself is rendered like so&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tableHeaders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Country&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Code&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Area&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Flag&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tableData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Brazil&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BR&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;area&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8,515,767 km2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🇧🇷&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt; &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;tableHeaders&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;tableData&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;
&lt;sup&gt;See &lt;a href="https://codesandbox.io/s/sticky-header-table-with-react-3j5zy?file=/src/App.js" rel="noopener noreferrer"&gt;App.js&lt;/a&gt;&lt;sup&gt;
&lt;/sup&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;where its &lt;code&gt;headers&lt;/code&gt; prop accepts an array of strings and &lt;code&gt;data&lt;/code&gt; is an array of objects.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;Table /&amp;gt;&lt;/code&gt;'s interface is not so crucial for the actual sticky  implementation and you can build your own abstraction.&lt;/p&gt;
&lt;h3&gt;
  
  
  &amp;lt;Table /&amp;gt; Component Implementation
&lt;/h3&gt;

&lt;p&gt;Below is the code behind &lt;code&gt;Table.js&lt;/code&gt;. It serves as a wrapper for the table and its sticky header.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Table.js&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;tableRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isSticky&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useStickyHeader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;renderHeader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;thead&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;thead&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isSticky&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;
          &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sticky"&lt;/span&gt;
          &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fixed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;renderHeader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;tableRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;renderHeader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tbody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;area&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flag&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tbody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;
&lt;sup&gt;View &lt;code&gt;Table.js&lt;/code&gt; in &lt;a href="https://codesandbox.io/s/sticky-header-table-with-react-3j5zy?file=/src/Table.js" rel="noopener noreferrer"&gt;CodeSandbox&lt;/a&gt;.&lt;sup&gt;
&lt;/sup&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;A few important aspects require a bit of details here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;tableRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isSticky&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useStickyHeader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://reactjs.org/docs/hooks-custom.html" rel="noopener noreferrer"&gt;custom React hook&lt;/a&gt; with two props exposed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;tableRef&lt;/code&gt; - used to ref the table element you want to have a sticky header for.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;isSticky&lt;/code&gt; - a flag turning &lt;code&gt;true&lt;/code&gt; whenever the table is over the page's top edge.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Render if isSticky is true.&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isSticky&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="c1"&gt;// This is a required &amp;lt;table /&amp;gt; wrapper for the sticky header.&lt;/span&gt;
  &lt;span class="c1"&gt;// .sticky class distinguishes from the original table&lt;/span&gt;
  &lt;span class="c1"&gt;// and the additional style enables the stickiness.&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;
    &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sticky"&lt;/span&gt;
    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fixed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Render the same table header */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;renderHeader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That part renders a sticky header if &lt;code&gt;isSticky&lt;/code&gt; is true.&lt;/p&gt;

&lt;p&gt;The sticky element above should inherit the original &lt;code&gt;&amp;lt;table /&amp;gt;&lt;/code&gt;'s styling in order to achieve the same appearance.&lt;/p&gt;

&lt;p&gt;Another thing to note - there are two calls of &lt;code&gt;renderHeader()&lt;/code&gt;. It means two &lt;code&gt;&amp;lt;thead /&amp;gt;&lt;/code&gt;s in the markup if stickiness is enabled. &lt;strong&gt;This is required. The original header needs to fill the physical space on top of the table. And it can't go sticky since &lt;code&gt;position: fixed&lt;/code&gt; takes elements &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/position#Syntax" rel="noopener noreferrer"&gt;out of their context&lt;/a&gt;. In this case introducing a second copy of the header is one way to address the issue.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  useStickyHeader() Implementation
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;useStickyHeader&lt;/code&gt; hook is probably the only piece of code you would need given the notes on the &lt;code&gt;&amp;lt;Table /&amp;gt;&lt;/code&gt; component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// useStickyHeader.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useStickyHeader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;defaultSticky&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isSticky&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsSticky&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;defaultSticky&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tableRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleScroll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bottom&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;bottom&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;68&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isSticky&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;setIsSticky&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;isSticky&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;setIsSticky&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isSticky&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleScroll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;handleScroll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tableRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBoundingClientRect&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scroll&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleScroll&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scroll&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleScroll&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;handleScroll&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;tableRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isSticky&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;
&lt;sup&gt;View &lt;code&gt;useStickyHeader.js&lt;/code&gt; in &lt;a href="https://codesandbox.io/s/sticky-header-table-with-react-3j5zy?file=/src/useStickyHeader.js" rel="noopener noreferrer"&gt;CodeSandbox&lt;/a&gt;.&lt;sup&gt;
&lt;/sup&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Quickly going through the code chunk by chunk.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isSticky&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsSticky&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;defaultSticky&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tableRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;useState&lt;/code&gt; provides a way to update the &lt;code&gt;isSticky&lt;/code&gt; flag based on some calculations. It takes a default value passed by the parent (the page may load with the table in the middle). &lt;code&gt;tableRef&lt;/code&gt; is simply a ref to the table element required for some calculations later on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleScroll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bottom&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// The number 68 is hardcoded here and is the header's height.&lt;/span&gt;
  &lt;span class="c1"&gt;// It could also be skipped&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;bottom&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;68&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isSticky&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;setIsSticky&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;isSticky&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;setIsSticky&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// returns a new memoized callback&lt;/span&gt;
  &lt;span class="c1"&gt;// whenever the value of isSticky changes&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isSticky&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here follow the necessary calculations. &lt;code&gt;{ top, bottom }&lt;/code&gt; describes the table's position on the screen. Once it starts passing off (&lt;code&gt;top &amp;lt;= 0&lt;/code&gt;) or there is a visual space for at least two headers (&lt;code&gt;bottom &amp;gt; 2 * 68&lt;/code&gt;) - the sticky mode is enabled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy9895664s180qubhrlmw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy9895664s180qubhrlmw.png" alt="Sticky table header"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The second part of the hook's implementation is its side effect. It does the scroll event binding and passes the current table dimensions down to the evaluation callback.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleScroll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Pass the current bounding rect of the table&lt;/span&gt;
    &lt;span class="nf"&gt;handleScroll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tableRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBoundingClientRect&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scroll&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleScroll&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Clear the effect&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scroll&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleScroll&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="c1"&gt;// Recreate the effect if handleScroll is a new function&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;handleScroll&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Final Words
&lt;/h2&gt;

&lt;p&gt;The full solution lives &lt;a href="https://codesandbox.io/s/sticky-header-table-with-react-3j5zy?file=/src/App.js" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Turning a table header sticky could be challenging in contrast to something made out of flexbox. It is frustrating to see that simply applying &lt;code&gt;position: fixed&lt;/code&gt; to the header doesn't magically work. And perhaps having to render two &lt;code&gt;&amp;lt;thead /&amp;gt;&lt;/code&gt;s is too much.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On the other hand tables come very handy at presenting array-like data with many default benefits.&lt;/strong&gt; That's why a separate blog post was dedicated to the header challenge. The minimum you would need to untangle it is a custom React hook being the main bolt.&lt;/p&gt;

&lt;h1&gt;
  
  
  📩
&lt;/h1&gt;

&lt;p&gt;If you face process or code challenges Google Search can't help you with, &lt;a href="https://webup.org/blog/subscribe/" rel="noopener noreferrer"&gt;join my readers group&lt;/a&gt;. I send monthly updates with posts like this.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://css-tricks.com/complete-guide-table-element/" rel="noopener noreferrer"&gt;A Complete Guide to the Table Element&lt;/a&gt; - deep into tables by Chris Coyier.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://css-tricks.com/accessible-simple-responsive-tables/" rel="noopener noreferrer"&gt;Accessible, Simple, Responsive Tables&lt;/a&gt; - approaching table layouts with flexbox.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://reactjs.org/docs/fragments.html" rel="noopener noreferrer"&gt;Fragments&lt;/a&gt; - React docs on Fragments with table splitting examples.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://reactjs.org/docs/hooks-custom.html" rel="noopener noreferrer"&gt;Building Your Own Hooks&lt;/a&gt; - the official guide behind custom hook extraction.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/position#Syntax" rel="noopener noreferrer"&gt;CSS: Cascading Style Sheets - position&lt;/a&gt; - more about &lt;code&gt;position: fixed&lt;/code&gt; on MDN.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://webup.org/blog/render-props-vs-hooks/" rel="noopener noreferrer"&gt;Render Props vs React Hooks&lt;/a&gt; - pattern comparison to help when deciding on component interfaces.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>tutorial</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Render Props vs React Hooks</title>
      <dc:creator>Miroslav Nikolov</dc:creator>
      <pubDate>Thu, 12 Nov 2020 07:51:28 +0000</pubDate>
      <link>https://dev.to/moubi/exploring-render-props-vs-react-hooks-1jk5</link>
      <guid>https://dev.to/moubi/exploring-render-props-vs-react-hooks-1jk5</guid>
      <description>&lt;p&gt;Can you guess which code snippet is more efficient and why?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3ayph0qlenl07wfcdhod.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3ayph0qlenl07wfcdhod.png" alt="Forms with useState and render props"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I started a &lt;a href="https://twitter.com/moubi/status/1271429303574556672" rel="noopener noreferrer"&gt;twitter discussion&lt;/a&gt; with the same questions, trying to understand if people have strong opinion about hooks and render props. Opposing the two is not a fantasy, but comes from a practical concern.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When it comes to state management &lt;em&gt;render prop component&lt;/em&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;is often &lt;strong&gt;more flexible and less error-prone&lt;/strong&gt; than pure hooks solution.&lt;/li&gt;
&lt;li&gt;is still suitable for &lt;strong&gt;the common&lt;/strong&gt; case.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In reality, hooks and render props shake hands and play well together. But if you must decide between either of the two, though, let's put that decision on stress.&lt;/p&gt;

&lt;p&gt;Want to see the end benchmark? Skip to the comparison, otherwise read on...&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If your are not familiar with hooks and the render props pattern - don't worry - a good starting point is &lt;a href="https://reactjs.org/docs/render-props.html" rel="noopener noreferrer"&gt;Render Props&lt;/a&gt;, &lt;a href="https://cdb.reacttraining.com/use-a-render-prop-50de598f11ce" rel="noopener noreferrer"&gt;Use a Render Prop!&lt;/a&gt; and &lt;a href="https://reactjs.org/docs/hooks-overview.html" rel="noopener noreferrer"&gt;Hooks at a Glance&lt;/a&gt;. A list of resources is also available at the end.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Render Props are Not Dead
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=pn0pIgdQvhU&amp;amp;list=PLCC436JpVnK0Q4WHoB85ZYBwcCyTaMgAl&amp;amp;index=6" rel="noopener noreferrer"&gt;A talk&lt;/a&gt; with that name by &lt;a href="https://twitter.com/erikras" rel="noopener noreferrer"&gt;Erik Rasmussen&lt;/a&gt; was the trigger for this writing. It outlines how we got from HoCs to hooks. Watch it, it should make things clearer.&lt;/p&gt;

&lt;p&gt;I remember the voice in my head hitting the play button on that React Europe video: &lt;em&gt;"Wait, should I do another rewrite of my library, getting rid of the render props I so much like"&lt;/em&gt;. At that time &lt;strong&gt;v2 of &lt;a href="https://github.com/moubi/enform" rel="noopener noreferrer"&gt;Enform&lt;/a&gt;&lt;/strong&gt; was released and I was happy with it. An immediate v3 rewrite would ruin my motivation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;May be you:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;work with hooks, but don't fully understand them&lt;/li&gt;
&lt;li&gt;see hooks as a magic solution&lt;/li&gt;
&lt;li&gt;want to rewrite it all with hooks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If so, then what follows may be a surprise.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Hooks and render props can solve the same problem. &lt;strong&gt;It is conceptually about moving state away from your components, so that it is reusable.&lt;/strong&gt; The question is which one does a better job? When? Does it matter to bother with wrapper components and render props since we already have the hooks API?&lt;/p&gt;

&lt;p&gt;To answer, let's work with the common form example below throughout this journey. It's trivial and you have probably seen it many times:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Form&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;
&lt;sup&gt;The form is intentionally kept simpler.&lt;sup&gt;
&lt;/sup&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;The snippet may force you to think: &lt;em&gt;"This is a recipe for disaster"&lt;/em&gt;. Right, and state is the primary suspect. Adding to that, usually you have more fields involved in the form and need to handle validation, submission, API calls, error messages too. Of course, as a result &lt;strong&gt;your component will grow and you may need to mitigate the state logic by abstracting it somehow.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Handling State Abstraction with Hooks
&lt;/h2&gt;

&lt;p&gt;Look at this simplified code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;This is a simple form!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;
&lt;sup&gt;Try it out in &lt;a href="https://codesandbox.io/embed/controlled-form-with-hooks-1e9o7?expanddevtools=1&amp;amp;fontsize=14&amp;amp;hidenavigation=1&amp;amp;module=%2Fsrc%2FApp.js&amp;amp;theme=dark" rel="noopener noreferrer"&gt;codesandbox&lt;/a&gt;&lt;sup&gt;
&lt;/sup&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;It is the same form component, but using a function instead of a class and the &lt;code&gt;useState&lt;/code&gt; hook.  Simple move that already made things nicer. Including more fields to this controlled form is as easy as handling more state in the component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPhone&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setAddress&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using hooks and functional components is already a win. OK, but you bump into another trouble - component state is growing together with the form. From that point there are two options. Create a separate form component or a custom hook to hold the state heavy lifting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Form Custom Hook
&lt;/h3&gt;

&lt;p&gt;I assume you know how to build one. There are many examples out there, so let's not focus on the &lt;code&gt;useForm&lt;/code&gt; implementation below. What is interesting is how it improves our component and how it gets consumed. Remember we are slowly getting to the pain point - would custom hook be the best approach here.&lt;/p&gt;

&lt;p&gt;Lastly, please excuse once again the simplicity as the idea is just to illustrate the pattern.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useForm&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;This is a simple form!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;
&lt;sup&gt;&lt;a href="https://codesandbox.io/embed/controlled-form-with-custom-hook-f810j?expanddevtools=1&amp;amp;fontsize=14&amp;amp;hidenavigation=1&amp;amp;module=%2Fsrc%2FApp.js&amp;amp;theme=dark" rel="noopener noreferrer"&gt;This codesandbox&lt;/a&gt; contains all the details.
&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Ideally adding more logic would result in just the &lt;code&gt;jsx&lt;/code&gt; (the render) part growing, while &lt;code&gt;useForm&lt;/code&gt; manages the state for you.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Side note:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;useForm()&lt;/code&gt; (it's a pretty common name) may miss-reference you to &lt;a href="https://github.com/react-hook-form/react-hook-form" rel="noopener noreferrer"&gt;react-hook-form&lt;/a&gt;. The name matches, but the idea is different. &lt;code&gt;react-hook-form&lt;/code&gt; is not solving the state problem described here, but avoiding it by having the form as uncontrolled instead.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Getting back to our example. Adding errors and submit features:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;submit&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useForm&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;This is a simple form!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;submit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;phone&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;phone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;phone&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Still, it scales pretty good. You can move more logic into the hook and make it reusable for all form components in your project.&lt;/p&gt;

&lt;p&gt;The state no longer resides in &lt;code&gt;&amp;lt;Form /&amp;gt;&lt;/code&gt;, but the component will continue to react on field  changes. At the end, it is the same &lt;code&gt;useState&lt;/code&gt; usage, but moved in &lt;code&gt;useForm&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The obvious benefits of this approach are that it's intuitive (no weird syntax), scales pretty well and it's probably part of the React future.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ok, but how about render props?&lt;/p&gt;




&lt;h2&gt;
  
  
  Handling State via Render Props
&lt;/h2&gt;

&lt;p&gt;Unloading the Form component state-wise using the render props approach requires you to create a wrapper component. So, no hooks on the surface, but a regular component. In this example it is &lt;code&gt;children&lt;/code&gt; that serves as a render prop, but you may use &lt;code&gt;render&lt;/code&gt; (or something else) instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;This is a simple form!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FormManager&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValue&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;FormManager&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;
&lt;sup&gt;Curious about &lt;code&gt;FormManager&lt;/code&gt;'s implementation? Here is the &lt;a href="https://codesandbox.io/embed/controlled-form-with-render-props-xvil0?expanddevtools=1&amp;amp;fontsize=14&amp;amp;hidenavigation=1&amp;amp;module=%2Fsrc%2FApp.js&amp;amp;theme=dark" rel="noopener noreferrer"&gt;codesandbox&lt;/a&gt;.&lt;sup&gt;
&lt;/sup&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Abstracting the state away in a weird way, right? Yes, this is how it is.&lt;/p&gt;

&lt;p&gt;From the official docs:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The term “render prop” refers to a technique for sharing code between React components using a prop whose value is a function.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;"...using a prop whose value is a function"&lt;/em&gt;&lt;/strong&gt; - exactly what seems awkward when you see render props for the first time. &lt;/p&gt;

&lt;p&gt;Other than that it works similar to &lt;code&gt;useForm&lt;/code&gt; except &lt;code&gt;&amp;lt;FormManager /&amp;gt;&lt;/code&gt; is just a normal component. This pattern might be familiar, especially if you are working on third party libraries or using such.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The render props approach has similar benefits to hooks, but looks strange and sometimes doesn't scale efficiently.&lt;/strong&gt; Why is that?&lt;/p&gt;

&lt;p&gt;Imagine the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Swipeable&lt;/span&gt;
      &lt;span class="na"&gt;onSwipeLeft&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSwipeLeft&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onSwipeRight&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSwipeRight&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;innerRef&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;innerRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DragDropContext&lt;/span&gt; &lt;span class="na"&gt;onDragEnd&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleDragEnd&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Droppable&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Draggable&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;provided&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
                        &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;provided&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;provided&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Draggable&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Droppable&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;DragDropContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Swipeable&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;
&lt;sup&gt;This snippet is actually a &lt;a href="https://github.com/moubi/flow-task/blob/master/src/components/Board/Board.js#L129" rel="noopener noreferrer"&gt;real example&lt;/a&gt;.&lt;sup&gt;
&lt;/sup&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Nested wrapper components with render props. Oh, that doesn't look very promising. It may even trick some people to believe the pattern is obsolete in favor of &lt;em&gt;"do everything with hooks"&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Hooks &lt;a href="https://reactjs.org/docs/hooks-faq.html#do-hooks-replace-render-props-and-higher-order-components" rel="noopener noreferrer"&gt;don't suffer the nesting issue&lt;/a&gt;, that's true.&lt;/p&gt;

&lt;p&gt;But if render props had no pros over hooks the article is leading to a dead end. There is something else, though, which is not about the syntax.&lt;/p&gt;

&lt;p&gt;Keep on...&lt;/p&gt;


&lt;h2&gt;
  
  
  Reality Check
&lt;/h2&gt;

&lt;p&gt;Let's recap. Remember this part from the beginning?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;This is a simple form!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    ...
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I intentionally left more elements (&lt;code&gt;&amp;lt;h1 /&amp;gt;&lt;/code&gt;) than just the &lt;code&gt;&amp;lt;form /&amp;gt;&lt;/code&gt; in the jsx. It is supposed to serve as a hint, because &lt;strong&gt;in reality some components aren't that simple&lt;/strong&gt;. Often they render more code which you don't have control over.&lt;/p&gt;

&lt;p&gt;A more realistic example would look like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useForm&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Navigation&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SomeOtherThirdPartyComponent&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Footer&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, I know you may say: &lt;em&gt;who uses jsx like that? You can obviously extract the form logic into another component and render it here instead&lt;/em&gt;. Yes and you would be right - seems the correct thing to do, but not always.&lt;/p&gt;

&lt;p&gt;There are three general restrictions with hooks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;you need &lt;a href="mailto:react@16.8.0"&gt;react@16.8.0&lt;/a&gt; (the one with hooks)&lt;/li&gt;
&lt;li&gt;you have to use functional components&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;you may fall into re-render issues&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Skipping the first two... If you have class components and a lower version of react you can't use hooks obviously. &lt;strong&gt;The third one, however, is the cornerstone when deciding between hooks and render props.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  You may Fall into Re-render Issues
&lt;/h3&gt;

&lt;p&gt;Given the last example, every time you type in the form fields &lt;code&gt;setValue&lt;/code&gt; will be called causing the whole &lt;code&gt;&amp;lt;Page /&amp;gt;&lt;/code&gt; component to re-render. And because you are updating the state, this is expected. But not desirable. &lt;strong&gt;Suddenly filling a form may become a very expensive operation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;React is clever enough to protect you from unnecessary renders, but it won't go against its principles. Every  component has its own catch-ups and you need to work around these, so it's safe against renders. &lt;/p&gt;

&lt;p&gt;Unfortunately, it may not be the case with &lt;code&gt;&amp;lt;Header /&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;Navigation /&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;Footer /&amp;gt;&lt;/code&gt; because, let's imagine, you don't have time to refactor them. And with &lt;code&gt;&amp;lt;SomeOtherThirdPartyComponent /&amp;gt;&lt;/code&gt; you may even not be able to do so.&lt;/p&gt;

&lt;p&gt;Not many options here. &lt;strong&gt;Extracting the from in a separate component is the way to go with hooks&lt;/strong&gt;. As a consequence - you will need to &lt;strong&gt;repeat that for every form&lt;/strong&gt; in your project, forcing the tree to grow inevitably.&lt;/p&gt;

&lt;p&gt;What if you are building a form library that exports a hook like &lt;code&gt;useForm&lt;/code&gt;? Do you prefer your users to do the extra extraction step above? Not a big deal you may say. Not a big one, but a less flexible one.&lt;/p&gt;

&lt;p&gt;Hooks are not remedy for all problems and they are not intended to serve that purpose. The hypothetical (or not) primer above is one of these cases where you may need the extra flexibility.&lt;/p&gt;

&lt;p&gt;Use the hooks, but add some sugar.&lt;/p&gt;

&lt;h3&gt;
  
  
  Re-render only What Is Relevant
&lt;/h3&gt;

&lt;p&gt;Render props don't suffer the same re-render issue hooks do. Here is why.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Navigation&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SomeOtherThirdPartyComponent&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FormManager&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValue&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;FormManager&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Footer&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;FormManager /&amp;gt;&lt;/code&gt; ensures whatever change is made in the form it will be isolated in that form.&lt;/strong&gt; &lt;code&gt;&amp;lt;Page /&amp;gt;&lt;/code&gt; is immune to unnecessary renders. You can add up more jsx with no side effects.&lt;/p&gt;

&lt;p&gt;Of course you can always break the useful pattern. Imagine updating some &lt;code&gt;&amp;lt;Page /&amp;gt;&lt;/code&gt; related state as a result of form manipulation. It will result in additional renders. But then, it won't be FormManager's fault.&lt;/p&gt;

&lt;p&gt;Now if your form library exports component with a render prop instead, its users get that extra flexibility. They are no longer forced to create additional components.&lt;/p&gt;




&lt;h2&gt;
  
  
  Comparison in Action
&lt;/h2&gt;

&lt;p&gt;Putting these two implementations side by side:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fr5pkjbtovrcxdv368z8y.gif" class="article-body-image-wrapper"&gt;&lt;img alt="Comparison between render props and custom hook form" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fr5pkjbtovrcxdv368z8y.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;sup&gt;Feel free to play with &lt;a href="https://codesandbox.io/embed/forms-that-cause-re-render-issue-sd6tn?expanddevtools=1&amp;amp;fontsize=14&amp;amp;hidenavigation=1&amp;amp;theme=dark" rel="noopener noreferrer"&gt;the set up&lt;/a&gt;.&lt;sup&gt;&lt;/sup&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Voilà. You can now see the render outcome of each form. The one on the left (custom hook) is causing re-renders in all Page children, while the one on the right (render prop) doesn't.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Words
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Render props are very useful if you want to isolate part of the jsx and inject some state without introducing side effects to your components.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is very common for many render prop implementations to use hooks internally so saying &lt;em&gt;"it's hooks or nothing"&lt;/em&gt; would be extreme. Hooks support the pattern pretty well and gain the extra flexibility they lack in some situations. This is to consider when deciding between one OR the other approach.&lt;/p&gt;

&lt;p&gt;But hey, your form library can also export both the wrapper component and the hook. This too is very common. That makes working on open source so fun.&lt;/p&gt;

&lt;h1&gt;
  
  
  📩
&lt;/h1&gt;

&lt;p&gt;If you face process or code challenges Google Search can't help you with, &lt;a href="https://webup.org/blog/subscribe/" rel="noopener noreferrer"&gt;join my readers group&lt;/a&gt;. I send monthly updates with posts like this.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;The list here is not extensive. Some of the topics are more advanced, some are touching just the basics. &lt;strong&gt;You are welcome to add to it.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://reactjs.org/docs/render-props.html" rel="noopener noreferrer"&gt;Render Props&lt;/a&gt; (React docs)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://reactjs.org/docs/hooks-overview.html" rel="noopener noreferrer"&gt;Hooks at a Glance&lt;/a&gt; (React docs)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cdb.reacttraining.com/use-a-render-prop-50de598f11ce" rel="noopener noreferrer"&gt;Use a Render Prop!&lt;/a&gt; (Michael Jackson)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/jaredpalmer/awesome-react-render-props" rel="noopener noreferrer"&gt;Awesome React Render Props&lt;/a&gt; (Jared Palmer)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=pn0pIgdQvhU&amp;amp;list=PLCC436JpVnK0Q4WHoB85ZYBwcCyTaMgAl&amp;amp;index=6" rel="noopener noreferrer"&gt;Render Props are Not Dead&lt;/a&gt; (Erik Rasmussen)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>discuss</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Do a Device Based Code Split in React</title>
      <dc:creator>Miroslav Nikolov</dc:creator>
      <pubDate>Fri, 06 Nov 2020 07:31:53 +0000</pubDate>
      <link>https://dev.to/moubi/thoughts-on-device-based-code-split-in-react-4n09</link>
      <guid>https://dev.to/moubi/thoughts-on-device-based-code-split-in-react-4n09</guid>
      <description>&lt;p&gt;This article is a mix of arguments, reality checks and a code solution at the end. &lt;strong&gt;Its focus: device (touch/desktop) driven code split in React with no backend.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Often the road leading to an actual implementation is long and bumpy - priorities, design, budget, colleagues with their own views, talking in different languages. These obstacles are challenging and usually take more energy to deal with than just coding. For that reason they deserve a separate preface here.&lt;/p&gt;

&lt;p&gt;Jump to the code section, if this is what you are looking for, otherwise let's continue.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It would be helpful if you already know what code splitting is. If not yet, the &lt;a href="https://reactjs.org/docs/code-splitting.html#code-splitting"&gt;"Code Splitting"&lt;/a&gt; writeup in the React docs is a good start.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Reality Check
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Many companies today prefer to build their web apps/sites targeting both touch and desktop devices, but would rather not invest in a separate mobile app.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Chiefs may not admit it, but the reasons spin around:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Building for the browser is fast and cheap.&lt;/li&gt;
&lt;li&gt;No need to involve the backend.&lt;/li&gt;
&lt;li&gt;Prizing "mobile first", but don't really align with that principle.&lt;/li&gt;
&lt;li&gt;Technical impediments to deliver a mobile app to the store.&lt;/li&gt;
&lt;li&gt;No budget.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Working in the browser is fast and reliable. There are many static site generators (&lt;a href="https://www.gatsbyjs.org/"&gt;Gatsby&lt;/a&gt;, &lt;a href="https://nextjs.org/"&gt;Nextjs&lt;/a&gt;, &lt;a href="https://v2.docusaurus.io/"&gt;Docusaurus&lt;/a&gt;) to support website creation with no backend knowledge required. &lt;a href="https://jamstack.org/what-is-jamstack/"&gt;Jamstack&lt;/a&gt; principles and tools make production deployments of a product easier than ever. Such tools are capable of bringing the "mobile first" concept to life, though it still remains wishful thinking.&lt;/p&gt;

&lt;p&gt;At the same time publishing a standalone mobile app to some app stores may turn into a nightmare. Read about &lt;a href="https://hey.com/apple/"&gt;the Hey saga&lt;/a&gt; fx. In contrast, javascript devs can quickly mockup a mobile version with the help of Chrome tools, so why hire an iOS/Android guy?&lt;/p&gt;

&lt;p&gt;All valid points and to add more, often you as a frontend professional won't get the chance to influence the final decision (especially in big companies). It is to be taken by product, marketing or finance teams.&lt;/p&gt;

&lt;p&gt;Native app or web app... Let's assume a decision is taken and you are left with no choice - &lt;strong&gt;a web app must be delivered (for desktop and mobile users)&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  If You Must Code Split
&lt;/h2&gt;

&lt;p&gt;Splitting react apps touch/desktop wise can be tricky if you have to do it in the frontend.&lt;/p&gt;

&lt;p&gt;Things to be considered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1️⃣ consider touch and desktop devices (&lt;strong&gt;when&lt;/strong&gt; to serve each app)&lt;/li&gt;
&lt;li&gt;2️⃣ decide on the split starting point (&lt;strong&gt;where&lt;/strong&gt; in the code)&lt;/li&gt;
&lt;li&gt;3️⃣ import only app specific components (&lt;strong&gt;how&lt;/strong&gt; to implement it)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;An answer to these three questions is important since maintainability, time, team motivation and other aspects very much depend on it.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  When a Device Is Considered Touch 1️⃣
&lt;/h2&gt;

&lt;p&gt;Usually you modify component's css to account for mobile devices.&lt;/p&gt;

&lt;p&gt;Perhaps the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.TopBar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;60px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="err"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Mobile */&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;768px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.TopBar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#ccc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="err"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;works well for you most of the time. Same component, but with different appearance based on browser's width. There is no problem with this approach and very often it is enough. Now one may argue that &lt;code&gt;max-width: 768px&lt;/code&gt; is sufficient to properly tell if a user is on a mobile device. Probably not. May be something like that is more accurate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;coarse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hover&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;You can read more about &lt;a href="https://css-tricks.com/interaction-media-features-and-their-potential-for-incorrect-assumptions/"&gt;interaction media features and their potential&lt;/a&gt; to determine device capabilities.&lt;/strong&gt; Consider it when deciding on the criteria for serving your mobile web app.&lt;/p&gt;




&lt;p&gt;Challenges arise when your company starts getting more serious about mobile users ("mobile first"). This could happen due to a separate strong design/UX and product teams being formed. &lt;strong&gt;In this reality your desktop and mobile websites/apps may end up drastically different. Business logic, pages, interactions and overall appearance are now unalike. Two independent versions of the same software.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;How does that translate in the React's language?&lt;/p&gt;

&lt;p&gt;For sure you won't be able to reuse every single component in both apps (touch and desktop). Same components/pages will require different data sets and behave non-identically (javascript logic). Others will be completely unique per app. &lt;strong&gt;In that case css adjustments as the one above may no longer be sufficient.&lt;/strong&gt; Interactions and data (javascript) need to be considered along with styling (css).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is where a proper split in the frontend must be done and it can't reside in your &lt;code&gt;.css&lt;/code&gt; files alone.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Where to Split the App 2️⃣
&lt;/h2&gt;

&lt;p&gt;It really depends. You have a few options considering requirements and design. &lt;strong&gt;One&lt;/strong&gt; is to split the app in its root. Maybe you have &lt;code&gt;PageRouter.js&lt;/code&gt; or just &lt;code&gt;App.js&lt;/code&gt; where page components are rendered based on the URL path. &lt;strong&gt;Second option&lt;/strong&gt; - split individual components. It is a good choice if pages for mobile and desktop are the same (or very similar), but some child components differ. You can also pick the &lt;strong&gt;third option&lt;/strong&gt; of using media queries in the css.&lt;/p&gt;

&lt;h3&gt;
  
  
  Split in the App's Root
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;This approach makes sense if your mobile and desktop apps are very different - separate pages, behavior, data and business logic in components.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's say there is a product details page (&lt;code&gt;&amp;lt;ProductDetails /&amp;gt;&lt;/code&gt;) on touch which doesn't exist in your desktop site. It displays detailed product information that otherwise would be part of &lt;code&gt;&amp;lt;Products /&amp;gt;&lt;/code&gt; when viewing on PC. On a phone, though, it might be too "noisy" to present so much data in a single page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;
   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;
   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;pages&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;touch&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;ProductDetails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;desktop&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;common&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;       &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;Checkout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;
   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;App&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;
&lt;sup&gt;See a &lt;a href="https://codesandbox.io/s/desktopmobile-code-split-sjbt0?file=/src/pages/touch/ProductDetails.js"&gt;working example&lt;/a&gt; in Codesandbox.&lt;/sup&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is this structure OK?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can look at &lt;code&gt;/touch&lt;/code&gt; and &lt;code&gt;/desktop&lt;/code&gt; folders as two separate apps, allowing for full control over their content.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easier maintenance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most pages in your app will be common - same names component-wise, but implementing app specific logic, which is great for maintenance.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bug fixing in isolation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having a bug in the products page on touch tells you that the cause is probably in &lt;code&gt;touch/Products.js&lt;/code&gt;. Fixing it there ensures your desktop page won't be affected.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Less side effects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Few more buttons for mobile or a dropdown on desktop? You can feel more comfortable implementing feature requests like that next time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adequate team collaboration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Implementing a products page means you have to do it for each app (two components). With the folder split above, it's easy to divide the work within the team without stepping on each other's toes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Split on Component Level
&lt;/h3&gt;

&lt;p&gt;Root level code split is often supplemented by splitting the &lt;code&gt;/components&lt;/code&gt; folder in a similar way. On the other hand, sometimes your desktop and mobile apps won't be very different. Only a few components deep in the tree may have an unalike data model or behavior. &lt;strong&gt;If you find yourself in any of these cases it might be useful to do a split per component&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;
   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;touch&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;TopBar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;TopBar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;desktop&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;TopBar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;TopBar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;common&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;       &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;Footer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;       &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;Footer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;
   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;pages&lt;/span&gt;
   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;App&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;&amp;lt;TopBar /&amp;gt;&lt;/code&gt; component has some data/behavior differences that require you to implement it separately for each app. In the same time &lt;code&gt;/common&lt;/code&gt; folder still contains all shared components.&lt;/p&gt;

&lt;p&gt;You can see how that is done for &lt;code&gt;/components&lt;/code&gt; in &lt;a href="https://codesandbox.io/s/desktopmobile-code-split-sjbt0?file=/src/components/touch/Product.js"&gt;products page example&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is this structure OK?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Adding to the pros of the previous section &lt;strong&gt;you will have less code to maintain&lt;/strong&gt;, since only a few components may require a split. Reusing app specific and shared components is also going to be straightforward.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ProductDescription&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../components/desktop/ProductDescription&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Products&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;
&lt;sup&gt;&lt;code&gt;pages/desktop/Products&lt;/code&gt; imports only components from &lt;code&gt;components/desktop&lt;/code&gt;.&lt;/sup&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Components with Styling Differences
&lt;/h3&gt;

&lt;p&gt;Should you create two copies of a component if it contains the same logic, but differs in styling? Looks like it should be shared and placed in the &lt;code&gt;/common&lt;/code&gt; folder, but at the same time its css will need the good old media query approach.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;768px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* OR */&lt;/span&gt;

&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;coarse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hover&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That looks ok. Is it the best thing you can do, though? &lt;strong&gt;What if the logic detecting mobile capabilities changes?&lt;/strong&gt; Should you change it everywhere? This is not optimal.&lt;/p&gt;

&lt;p&gt;Ok, what to do?&lt;/p&gt;

&lt;p&gt;Ideally the logic for detecting touch devices should be central for the app. Getting a desktop or mobile component to render should be a matter of simply tweaking a prop.&lt;/p&gt;

&lt;p&gt;Imagine this structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;
   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;touch&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;TopBar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;TopBar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;desktop&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;TopBar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;TopBar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;common&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;       &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;TopBarLinks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;
   &lt;span class="o"&gt;|&lt;/span&gt;       &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;TopBarLinks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;
   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;pages&lt;/span&gt;
   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;App&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;&amp;lt;TopBarLinks /&amp;gt;&lt;/code&gt; is a shared component and may have some visual diffs. In its css this is addressed with a class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.TopBarLinks&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;         &lt;span class="c"&gt;/* Desktop */&lt;/span&gt;
&lt;span class="nc"&gt;.TopBarLinks.touch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;   &lt;span class="c"&gt;/* Mobile */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then it is used both in &lt;code&gt;desktop/TopBar&lt;/code&gt; and &lt;code&gt;touch/TopBar&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// desktop/TopBar.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TopBar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TopBar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Logo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../assets/logo.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TopBarLinks&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// touch/TopBar.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TopBar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TopBar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Logo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../assets/logo.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TopBarLinks&lt;/span&gt; &lt;span class="nx"&gt;touch&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. This is how you can render shared components with visual diffs. &lt;strong&gt;As a result the css file is cleaner and independent of the device detection logic.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Enough said on the possibilities for organizing the codebase. Now, how to glue things together.&lt;/p&gt;




&lt;h2&gt;
  
  
  Load Components on Demand 3️⃣
&lt;/h2&gt;

&lt;p&gt;No matter where the split resides in - application root or individual components, or perhaps both -  its implementation is going to be the same. Ultimately the pages from all earlier examples are also components.&lt;/p&gt;

&lt;p&gt;The task is to load only desktop &lt;strong&gt;OR&lt;/strong&gt; touch related code in the browser. Loading the whole bundle (all components), but using (rendering) only device specific slices may work, but it's not optimal. A proper implementation requires you to use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Dynamic_Imports"&gt;dynamic import()&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;React docs tell you that &lt;a href="https://reactjs.org/docs/react-api.html#reactsuspense"&gt;Suspense&lt;/a&gt; relies on that principle underneath and will probably do the job. You could also base your solution on &lt;a href="https://github.com/gregberge/loadable-components"&gt;loadable-components&lt;/a&gt; library. For the sake of simplicity and to cover the specific use case of touch/desktop based split, let's further focus on a plain solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conditionally Import and Render Components
&lt;/h3&gt;

&lt;p&gt;I personally imagine the following in the application root (&lt;code&gt;App.js&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Import&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Import&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Product&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Import&lt;/span&gt;
        &lt;span class="nx"&gt;touch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./touch/Products&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
        &lt;span class="nx"&gt;desktop&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./desktop/Products&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Product&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Product&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Import&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;
&lt;sup&gt;See it in the &lt;a href="https://codesandbox.io/s/desktopmobile-code-split-sjbt0?file=/src/App.js"&gt;example Codesandbox app&lt;/a&gt;.&lt;/sup&gt;
&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;Import /&amp;gt;&lt;/code&gt; component (you can name it differently) accepts two props - &lt;code&gt;desktop&lt;/code&gt; and &lt;code&gt;touch&lt;/code&gt;. They expect a function returning a dynamic import call. In the example above there are two independent &lt;code&gt;&amp;lt;Product /&amp;gt;&lt;/code&gt; page components that you may want to import/render conditionally.&lt;/p&gt;

&lt;p&gt;The third prop is a &lt;code&gt;children&lt;/code&gt; function that does the actual rendering. An obvious benefit of using render prop function here is the opportunity to explicitly pass any props to your component if needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Product&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Product&lt;/span&gt;
    &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Implementation Details
&lt;/h3&gt;

&lt;p&gt;What will &lt;code&gt;Import&lt;/code&gt; do internally is to: evaluate which component to load and pass it down as an argument to the render prop function.&lt;/p&gt;

&lt;p&gt;Basic implementation may look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Detect touch enabled devices based on interaction media features&lt;/span&gt;
&lt;span class="c1"&gt;// Not supported in IE11, in which case isMobile will be 'false'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isMobile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;matchMedia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(pointer: coarse) and (hover: none)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Import&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;touch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;desktop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setComponent&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Assign a callback with an import() call&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;importCallback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isMobile&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;touch&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;desktop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Executes the 'import()' call that returns a promise with&lt;/span&gt;
    &lt;span class="c1"&gt;// component details passed as an argument&lt;/span&gt;
    &lt;span class="nx"&gt;importCallback&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;componentDetails&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Set the import data in the local state&lt;/span&gt;
      &lt;span class="nx"&gt;setComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;componentDetails&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;desktop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;touch&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="c1"&gt;// The actual component is assigned to the 'default' prop&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;
&lt;sup&gt;More on Import and its usage - check &lt;a title="Import component" href="https://codesandbox.io/s/desktopmobile-code-split-sjbt0?file=/src/Import.js"&gt;the app context&lt;/a&gt;.&lt;/sup&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Some notes:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;window.matchMedia("(pointer: coarse) and (hover: none)")&lt;/code&gt; - you can use any other mechanism for detecting touch capabilities here. Going a step further, &lt;code&gt;isMobile&lt;/code&gt; may come from the store instead (if you are using redux, mobx or other global state management mechanism).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;importCallback().then(componentDetails)&lt;/code&gt; - the actual component is set in &lt;code&gt;componentDetails.default&lt;/code&gt; and you have to export it using default export (&lt;code&gt;export default function Products()&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, imported data is set to the local state and your component passed down to the children function for rendering.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Using &lt;code&gt;import()&lt;/code&gt; requires some prerequisites to allow for proper parsing and dividing the final bundle in parts. You may need to additionally set these up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Webpack Config
&lt;/h3&gt;

&lt;p&gt;For the split to work there are some &lt;a href="https://webpack.js.org/guides/code-splitting/"&gt;adjustments in the webpack config&lt;/a&gt; file to be made. An example config by &lt;a href="https://overreacted.io"&gt;Dan Abramov&lt;/a&gt; can be &lt;a href="https://gist.github.com/gaearon/ca6e803f5c604d37468b0091d9959269"&gt;found on github&lt;/a&gt;. If you are using &lt;strong&gt;Create React App&lt;/strong&gt; that is done by default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;main&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/App.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bundle.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;chunkFilename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chunk.[id].js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./dist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;publicPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Babel Plugin
&lt;/h3&gt;

&lt;p&gt;If you are using Babel the &lt;a href="https://www.npmjs.com/package/@babel/plugin-syntax-dynamic-import"&gt;@babel/plugin-syntax-dynamic-import&lt;/a&gt; plugin is required in order to properly parse dynamic imports.&lt;/p&gt;

&lt;h3&gt;
  
  
  Eslint Config
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/eslint-plugin-import"&gt;eslint-plugin-import&lt;/a&gt; is also required to support export/import syntax. Don't forget to update your eslint config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;babel-eslint&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;import&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again code splitting is supported by default with &lt;a href="https://create-react-app.dev/docs/code-splitting"&gt;Create React App&lt;/a&gt; and you can skip the config steps in that case.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Words
&lt;/h2&gt;

&lt;p&gt;Check &lt;a href="https://codesandbox.io/s/desktopmobile-code-split-sjbt0?file=/src/App.js"&gt;the full code implementation in Codesandbox&lt;/a&gt; for details on device based code splitting.&lt;/p&gt;

&lt;p&gt;I would like to wrap up by sharing my own motivation for having app structure like the one described. It may not be your case, but my observations show a common mindset especially in big corps where a clear separation between product, backend and frontend is in place. &lt;/p&gt;

&lt;p&gt;In that reality it's much easier (and often the only thing you can do) to overcome process issues with a tech solution, instead of trying to change people. &lt;/p&gt;

&lt;p&gt;Here is an example: you know that backend will deliver the API in a week, but you also know that you can deliver the UI today. Waiting one week for the backend? The slow backend delivery might be due to organizational issues. The tech solution in that case is to mock the payload and deliver to QA and Product teams early.&lt;/p&gt;

&lt;p&gt;The same motive plays its role when trying to avoid the backend by carefully code splitting the app.&lt;/p&gt;

&lt;p&gt;Frontend-only app split will allow for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;development speed&lt;/strong&gt; as per less backend deps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;flexibility&lt;/strong&gt; when changes are requested&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;It also means less headache by not having to confront colleagues and management, and higher confidence as you remain in the javascript land - your comfortable area of expertise.&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  📩
&lt;/h1&gt;

&lt;p&gt;If you face process or code challenges Google Search can't help you with, &lt;a href="https://webup.org/blog/subscribe/"&gt;join my readers group&lt;/a&gt;. I send monthly updates with posts like this.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://reactjs.org/docs/code-splitting.html"&gt;Code-Splitting - React&lt;/a&gt; - from React's official docs.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://create-react-app.dev/docs/code-splitting/"&gt;Code Splitting - Create React App&lt;/a&gt; - words on code splitting in create-react-app.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://reactjs.org/docs/concurrent-mode-suspense.html"&gt;Suspense for Data Fetching&lt;/a&gt; - get an overview on how and when to use React Suspense.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://webpack.js.org/guides/code-splitting/"&gt;Webpack Code Splitting&lt;/a&gt; - configure webpack to support code split in your React app.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://loadable-components.com/docs/getting-started/"&gt;Loadable Components - Guide&lt;/a&gt; - Getting started guide for &lt;a href="https://github.com/gregberge/loadable-components"&gt;loadable-components&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://css-tricks.com/interaction-media-features-and-their-potential-for-incorrect-assumptions/"&gt;Interaction Media Features and Their Potential&lt;/a&gt; - how to better determine device capabilities with media queries.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>mobile</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
