<?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: MasuqaT</title>
    <description>The latest articles on DEV Community by MasuqaT (@occar421).</description>
    <link>https://dev.to/occar421</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%2F59375%2F9bc9b9e7-ad42-44ae-b373-2532f9b6ddab.png</url>
      <title>DEV Community: MasuqaT</title>
      <link>https://dev.to/occar421</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/occar421"/>
    <language>en</language>
    <item>
      <title>Event handlers should be optional</title>
      <dc:creator>MasuqaT</dc:creator>
      <pubDate>Mon, 18 Oct 2021 12:42:54 +0000</pubDate>
      <link>https://dev.to/occar421/event-handlers-should-be-optional-2p01</link>
      <guid>https://dev.to/occar421/event-handlers-should-be-optional-2p01</guid>
      <description>&lt;p&gt;&lt;a href="https://blog.masuqat.net/2021/08/28/event-handler-props-should-be-optional/"&gt;Japanese Version | 日本語版&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I realized that a component still works fine even if they do not receive event handlers. I explain why making event handlers optional makes sense and recommend doing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Component's event handlers to whom?
&lt;/h2&gt;

&lt;p&gt;The event handlers of a component are defined for the caller, the parent component.&lt;/p&gt;

&lt;p&gt;Thinking about the necessity of the events and event handlers in the component, they are used to realize the inverse data flow. Since "components should only update their own state", when it receives the data from its parent, indirectly expresses an update as an event, notifies it to its parent through the callback a.k.a. event handler, ask its parent to update the data. ref: &lt;a href="https://reactjs.org/docs/thinking-in-react.html#step-5-add-inverse-data-flow"&gt;Thinking in React - Step 5: Add Inverse Data Flow&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Be aware that the event handlers, passed from the parent, do not affect directly on the (child) component. Of course, it looks as if it affects the (child) component when they are combined in the app, however, just the parent component changes itself instead of the (child) component. The parent component receives an event from the child through the event handlers, changes its state base on the event, then finally passes the updated data to the child. The parent component do not necessarily have to utilize the event and still be able to pass arbitrary data to the (child) component. Including whether to utilize the event or not, the update logic is fully under the parent's decision. In other words, the child component should not know about how the events and the event handlers are used in the parent component or others &lt;sup id="fnref1"&gt;1&lt;/sup&gt;. Even if the event handler is &lt;code&gt;undefined&lt;/code&gt; because of not passed from the parent, the child component does not change its self behavior.&lt;/p&gt;

&lt;p&gt;Actually, all the event handlers for HTML elements are optional. We don't need to use &lt;code&gt;focusin&lt;/code&gt; or &lt;code&gt;input&lt;/code&gt; event and pass event handlers to all the events (except framework development). Moreover, HTML elements still work fine (raise no errors) even though we don't pass event handlers.&lt;/p&gt;

&lt;p&gt;Since Vue and Angular use HTML based notation, event handlers are naturally regarded as optional. While in React, because it expresses event handlers as props like a value, event handlers tend to be marked as required. To avoid that, we need to call event handlers with optional chaining (&lt;code&gt;?.&lt;/code&gt;) thoroughly, then add &lt;code&gt;?&lt;/code&gt; to the type if in TypeScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  That said, isn't it necessary sometimes?
&lt;/h2&gt;

&lt;p&gt;I believe everything will be still well even if we make all "event handlers" optional.&lt;/p&gt;

&lt;h3&gt;
  
  
  Function prop doesn't mean event handler
&lt;/h3&gt;

&lt;p&gt;The type of the event handlers may be like &lt;code&gt;(...args: [...Args]) =&amp;gt; void&lt;/code&gt;, returns nothing. In some cases, the props includes normal functions which are not event handlers. For example, data fetching function &lt;code&gt;(...args: [...Args]) =&amp;gt; Promise&amp;lt;Data&amp;gt;&lt;/code&gt;&lt;sup id="fnref2"&gt;2&lt;/sup&gt;. These functions are required for the component to work fine. However, they are actually not event handlers and not related to this opinion, event handlers should be optional.&lt;/p&gt;

&lt;h3&gt;
  
  
  Component in cooperative group
&lt;/h3&gt;

&lt;p&gt;As I mentioned that, even though the component is assumed to be work cooperatively in practice with the parent or others through the event handlers, receiving event handlers does not mean they are required for the single component (might be useless for others without passing event handlers). Passing event handlers is necessary to realize the behavior for a cooperative group, but as the parent-child relation of the component, as I mentioned above, it is just the problem how the cooperative group uses the event and not the problem of the single component as a primitive piece in the group.&lt;/p&gt;

&lt;p&gt;Similarly in HTML elements, for example of &lt;code&gt;&amp;lt;button type="button" /&amp;gt;&lt;/code&gt;, (in normal use) it is not useful without use of &lt;code&gt;click&lt;/code&gt; event, but that button does not raise an error. Because the parent component cannot achieve the requirement without &lt;code&gt;click&lt;/code&gt; event or others, it pass event handlers to that button.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inconvenience of required event handlers
&lt;/h2&gt;

&lt;p&gt;Lastly, I list problems if event handlers are not optional.&lt;/p&gt;

&lt;h3&gt;
  
  
  Component catalog or test
&lt;/h3&gt;

&lt;p&gt;In a component catalog, we explain many variations of the component. If event handlers are required, we have to pass made-up event handlers&lt;sup id="fnref3"&gt;3&lt;/sup&gt; though they are not necessary in a catalog. Maybe, notifying the emit of the event is helpful only in the demo for behavior and not helpful for explaining color or size variants. (Remember that the long list of code for color and size variation of a basic button component with &lt;code&gt;onClick={action("clicked")}&lt;/code&gt; in each item.)&lt;/p&gt;

&lt;p&gt;The same is true for the test. If event handlers are required, we have to pass unnecessary event handlers for the test view point and the test purpose goes unclear. Also it increases boilerplate even in a test.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conditionally unnecessary
&lt;/h3&gt;

&lt;p&gt;Depending on the parameters, sometimes it is obvious that there are event handlers which are never called. For example, &lt;code&gt;click&lt;/code&gt; event when &lt;code&gt;&amp;lt;button /&amp;gt;&lt;/code&gt; is &lt;code&gt;disabled&lt;/code&gt;. Aside from why&lt;sup id="fnref4"&gt;4&lt;/sup&gt; there are permanently disabled control elements in SPA, it is a bad interface for a component user that has obviously unnecessary event handlers but necessary to pass something.&lt;/p&gt;

&lt;p&gt;Previously, I put &lt;code&gt;const noop = () =&amp;gt; {};&lt;/code&gt; to the required &lt;code&gt;onChange&lt;/code&gt; prop of &lt;code&gt;&amp;lt;input /&amp;gt;&lt;/code&gt;-like component which is sometimes permanently disabled for the fixed value. I still regret doing that.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;As an interface which satisfies the requirement, e.g. the identifier names and parameters, the components need to "reach the consensus" with its generic(unspecified) parent. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;I think most of the components should receive fetched data as a value prop, not through invoking a function prop. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;Usually they are just a boilerplate such as Storybook Actions or &lt;code&gt;console.log&lt;/code&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;E.g. listing uneditable values along with normal editable values, brief promotion with button like "Coming Soon", etc. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>frontend</category>
      <category>codequality</category>
      <category>coding</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Component variant with View-Hook Pair</title>
      <dc:creator>MasuqaT</dc:creator>
      <pubDate>Sun, 05 Sep 2021 12:55:58 +0000</pubDate>
      <link>https://dev.to/occar421/component-variant-with-view-hook-pair-3nli</link>
      <guid>https://dev.to/occar421/component-variant-with-view-hook-pair-3nli</guid>
      <description>&lt;p&gt;&lt;a href="https://blog.masuqat.net/2021/08/21/component-variant-with-view-hook-pair/" rel="noopener noreferrer"&gt;Japanese Version | 日本語版&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://dev.to/occar421/view-hook-pair-pattern-draft-5fjd"&gt;my previous post&lt;/a&gt;, I introduced View-Hook Pair pattern. In this post, I describe how to implement a component with some variations with View-Hook Pair. Using it, we can achieve the modular frontend component without lacking the flexibility of spec change or refactoring-ability.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/MasuqaT-NET/BlogExamples/tree/master/Web/React/component-variant-with-view-hook-pair" rel="noopener noreferrer"&gt;Example code&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Variation of the component
&lt;/h2&gt;

&lt;p&gt;During creating a web application, there are the visually similar component with almost the same usecase and the same place. It is because that, some parts look/behave a bit different according to its attribute, feature flags, customize by users, and so on.&lt;/p&gt;

&lt;p&gt;In this post, I bring up the example of a simple file viewer app with the component with the 2 variations. This app has 2 panes, the file list on the left and the detail on the right. Especially for an image file or a movie file, the detail pane additionaly shows the thumbnails (actually a made-up image).&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%2Fuploads%2Farticles%2Fxyvsiptzp7asx88jxdf9.jpeg" 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%2Fuploads%2Farticles%2Fxyvsiptzp7asx88jxdf9.jpeg" alt="Initial look"&gt;&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%2Fuploads%2Farticles%2Fik1t0684x2dhe5pzee0j.jpeg" 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%2Fuploads%2Farticles%2Fik1t0684x2dhe5pzee0j.jpeg" alt="For a normal file"&gt;&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%2Fuploads%2Farticles%2Fsr781pa07fsq754b5bex.jpeg" 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%2Fuploads%2Farticles%2Fsr781pa07fsq754b5bex.jpeg" alt="For a media file"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this time, I regard the difference of the detail pane as a variation.&lt;/p&gt;

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

&lt;p&gt;Of course we hope all the components are highly maintainable. However, for the component shared part of the variants, it is hard. The spec change could leads code changes in many place due to duplication and/or forgetting the necessary changes. It costs more and has higher congnitive load than the usual components. We need to avoid them somehow.&lt;/p&gt;

&lt;p&gt;Though there are several naive implementation for the component with the variants, it would cause problems when the component gets complex/large.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code changes in many place or miss by the duplication when the variants are implemented with the respective components.&lt;/li&gt;
&lt;li&gt;Difficult to change by the branch conditions when the varitants are implemented as the single component which changes UI/behavior by the parameters.&lt;/li&gt;
&lt;li&gt;The component requires unnecessary props for some variants and it is difficult to express as the type.&lt;/li&gt;
&lt;li&gt;Though we initially achieve the good shared parts or the good branch flows, it won't be that good after it adds many features.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I assume View-Hook Pair ease these problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  View-Hook Pair
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/occar421/view-hook-pair-pattern-draft-5fjd"&gt;View-Hook Pair&lt;/a&gt; is, I previously proposed, an idea for divide-and-conquar method which consists with the formmaly defined pair of View and Hook. The former covers UI code and the latter covers state and logic.&lt;/p&gt;

&lt;p&gt;In this post, I defined the "Standard form" against the problem like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useObject&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="nx"&gt;Dependencies&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ViewProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Exports&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;{}]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;View&lt;/span&gt;&lt;span class="p"&gt;({}:&lt;/span&gt; &lt;span class="nx"&gt;ViewProps&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ReactElement&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;&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="k"&gt;export&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I newly propose the objects &lt;code&gt;Dependencies&lt;/code&gt; and &lt;code&gt;Exports&lt;/code&gt;. These are optional to use and we are also be able to implement the example project without these objects.&lt;/p&gt;

&lt;p&gt;The former object &lt;code&gt;Dependencies&lt;/code&gt; would be the port of Dependency Injection pattern. This is to the component free from the (static and technically detailed) external dependency with the side-effect and/or resource fetching, like the server layered architecture. &lt;/p&gt;

&lt;p&gt;The latter object &lt;code&gt;Exports&lt;/code&gt; would be the public methods/properties of Object-Oriented Programming class. These &lt;code&gt;useObject&lt;/code&gt; "class" exchange messages with others through their "public" interfaces.&lt;/p&gt;

&lt;p&gt;When to integrate the pair, integrate it in where it is used. For example, the component which uses &lt;code&gt;Component&lt;/code&gt; with &lt;strong&gt;non&lt;/strong&gt; View-Hook Pair form and the unit tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tactics
&lt;/h2&gt;

&lt;p&gt;From here, I describe how to implement the pair using child pairs.&lt;/p&gt;

&lt;p&gt;First, make the normal component for the shared part. We don't need to use View-Hook Pair for a (simple) Presentational component or the one only with small logic and scoped state. If not and necessary, like "Standard form" above, split the component into the pair. That said, usually we just put the component states and callbacks to &lt;code&gt;ViewProps&lt;/code&gt;, the functions run in &lt;code&gt;useEffect&lt;/code&gt; like &lt;code&gt;componentWillMount&lt;/code&gt; to &lt;code&gt;Exports&lt;/code&gt;, and declarative UI (including animation state) to &lt;code&gt;View&lt;/code&gt;, respectively.&lt;/p&gt;

&lt;p&gt;In a View-Hook Pair form component which uses View-Hook Pair form components, combine Views and Hooks independently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useObject&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="nx"&gt;Dependencies&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ViewProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Exports&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;childProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;childExports&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useObject&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="nx"&gt;childProps&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{}]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;View&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;childProps&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ViewProps&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;childProps&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;useObject&lt;/code&gt; in the parent component, it combines its &lt;code&gt;Prop&lt;/code&gt;, &lt;code&gt;Dependencies&lt;/code&gt;, and children's &lt;code&gt;useObject&lt;/code&gt;s and &lt;code&gt;Exports&lt;/code&gt;s to implement its responsibility. In &lt;code&gt;View&lt;/code&gt;, using HTML element and other component, it places children's &lt;code&gt;View&lt;/code&gt;s and mark up its whole look. Maybe, its &lt;code&gt;ViewProps&lt;/code&gt; has some structure to prevent the flood of flat children's &lt;code&gt;ViewProps&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;At the top component which finally integrates the pair to the normal form, like &lt;code&gt;Component_&lt;/code&gt; above, call &lt;code&gt;useObject&lt;/code&gt;, do necessary process, then finally call &lt;code&gt;View&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The flow of process is like this.&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%2Fuploads%2Farticles%2F3p67qmqhzberwxnaq1rs.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%2Fuploads%2Farticles%2F3p67qmqhzberwxnaq1rs.png" alt="Flow of process"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(Actually, the order is arbitrary for the &lt;code&gt;View&lt;/code&gt;s in the same depth.)&lt;/p&gt;

&lt;p&gt;In the tree of Hook side, the parent Hook can create its &lt;code&gt;ViewProps&lt;/code&gt; and &lt;code&gt;Exports&lt;/code&gt; by referencing children's encapsulated states from &lt;code&gt;Exports&lt;/code&gt;s, in postorder. It is difficult to achieve with normal React component method except with redundant(duplicated) statea. In the tree of View side, the tree structure is almost the same and rendered in the similar order.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example through the project
&lt;/h2&gt;

&lt;p&gt;I pick some code for the component implementing variants from &lt;a href="https://github.com/MasuqaT-NET/BlogExamples/tree/master/Web/React/component-variant-with-view-hook-pair" rel="noopener noreferrer"&gt;Example code&lt;/a&gt;. For the rest of the component, check 'src/Panel'. I don't mention the other components because it is off-topic.&lt;/p&gt;

&lt;p&gt;As I mentioned the example project in the first section of this post, its detail pane has 2 variations which is for media files and for others. In this example, they are implemented separatedly as &lt;code&gt;MediaPanel&lt;/code&gt; and &lt;code&gt;TextPanel&lt;/code&gt; respectively (both components are located in 'src/Panel'). Both are "Parent" in the figure above and they share their contents in 'src/Panel/parts', except the spacing and the behavior/UI only in one.&lt;/p&gt;

&lt;p&gt;First, I show the &lt;code&gt;TextPanel&lt;/code&gt; which is easier. (Style definitions are excluded because it is off-topic.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&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="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Dependencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useObject&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;Props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}:&lt;/span&gt; &lt;span class="nx"&gt;Dependencies&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;attributesProps&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useObject&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="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;attributesProps&lt;/span&gt; &lt;span class="p"&gt;}];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;View&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;attributesProps&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;useObject&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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="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="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="nc"&gt;Header&lt;/span&gt; &lt;span class="na"&gt;name&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="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;&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="nc"&gt;Attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;attributesProps&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;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;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TextPanel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It uses normal form &lt;code&gt;Header&lt;/code&gt; shared component and View-Hook Pair form &lt;code&gt;Attributes&lt;/code&gt; shared component. I placed &lt;code&gt;&amp;lt;div /&amp;gt;&lt;/code&gt; to add spacing because it is responsibility of this component.&lt;/p&gt;

&lt;p&gt;Then, I show the Hook of &lt;code&gt;MediaPanel&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Dependencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;getPreviewUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&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;function&lt;/span&gt; &lt;span class="nf"&gt;useObject&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getPreviewUrl&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Dependencies&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;previewUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPreviewUrl&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&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;previewProps&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Preview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useObject&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;previewUrl&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;attributesProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;editing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;attributesEditing&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useObject&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;load&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="k"&gt;async &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;setPreviewUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setPreviewUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPreviewUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getPreviewUrl&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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attributesEditing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;previewProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attributesProps&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;load&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&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;It additionally uses &lt;code&gt;Preview&lt;/code&gt; shared component  because &lt;code&gt;MediaPanel&lt;/code&gt; has a preview not like &lt;code&gt;TextPanel&lt;/code&gt;. Then, &lt;code&gt;MediaPanel&lt;/code&gt; has a requirement to stop the animation during editing &lt;code&gt;Attributes&lt;/code&gt;, so it uses &lt;code&gt;Exports&lt;/code&gt; of &lt;code&gt;Attributes.useObject&lt;/code&gt;. Furthermore, it exports &lt;code&gt;load&lt;/code&gt; in &lt;code&gt;Exports&lt;/code&gt; to make the parent be able to control the load timing of it.&lt;/p&gt;

&lt;p&gt;Finally, I show the View of &lt;code&gt;MediaPanel&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;View&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;attributesEditing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;previewProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;attributesProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;useObject&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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="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;previewHovered&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPreviewHovered&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="kc"&gt;false&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="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="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;previewHovered&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;attributesEditing&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;style&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;Header&lt;/span&gt; &lt;span class="na"&gt;name&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="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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;onMouseEnter&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setPreviewHovered&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="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onMouseLeave&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setPreviewHovered&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="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;Preview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;previewProps&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;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="nc"&gt;Attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;attributesProps&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;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;It just pass the props for the children's &lt;code&gt;ViewProps&lt;/code&gt;s. Apart from that, it has &lt;code&gt;previewHovered&lt;/code&gt; state for the UI decoration. (View-Hook Pair is to sweep out information state and logic from &lt;code&gt;View&lt;/code&gt; and it doesn't mean to prohibit any kind of state. The state and logic are allowed which is only for the decoration.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Cons
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Though it helps the essential part (in sence the of spec) to be well shared, this pattern forces many boilerplates.&lt;/li&gt;
&lt;li&gt;Conditional or loop process. This is due to React Hooks restriction. It also could be a problem when the View and Hook is located in the different depth in the tree.&lt;/li&gt;
&lt;li&gt;Typing for the pair. Declaring all the type and impose the pair or referring the actual implementation dynamically. (This example uses latter one.)&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;To explain the usage of View-Hook Pair, I describe the implementation for the component with variations to prevent the maintainability problem.&lt;/p&gt;

</description>
      <category>react</category>
      <category>designpatterns</category>
      <category>codequality</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Separate Presentation "System" first in the frontend architecture</title>
      <dc:creator>MasuqaT</dc:creator>
      <pubDate>Sun, 04 Jul 2021 11:38:06 +0000</pubDate>
      <link>https://dev.to/occar421/separate-presentation-system-first-in-the-frontend-architecture-59np</link>
      <guid>https://dev.to/occar421/separate-presentation-system-first-in-the-frontend-architecture-59np</guid>
      <description>&lt;p&gt;&lt;a href="https://blog.masuqat.net/2021/05/29/separate-presentation-system-first-in-frontend-architecture/"&gt;Japanese Version | 日本語版&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am working on the SPA which is becoming fat and complex due to its (proper and necessary) requirement and difficulty. I want to manage the problems before they become too big to deal with.&lt;/p&gt;

&lt;p&gt;In this article, I try to re-introduce the rough structure to the frontend architecture, between the UI components and API access objects, to divide them and ease the complexity. I hope this helps you to organize the problems, to review the code, and to avoid "unnecessary" consideration.&lt;/p&gt;

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

&lt;p&gt;I observed that the practice such as layering, UI component classification, and component composition is widely spread among the community today for the middle size components. By putting the responsibility of the visual to the Presentational Component, the logic/data process is well managed in the Container Component. It reduces the chance of mixing the visual and logic/data process, which leads it to the "legacy" code.&lt;/p&gt;

&lt;p&gt;On the other hand, I sometimes feel that there is no good rule nor guideline in the codebase between the UI components and the API access objects. When the logic/data process becomes fat, we would use the library called the Store such as Redux + async plugin, MobX, and (your favorite library) to ease the complexity. Though with that, the store becomes fat/complex too unless there is a good rule. These fatness/complexity usually would not be recognized until the new members point out it or they get confused. It is also the high congnitive load for whom understands codebase well, due to the team mates' change.&lt;/p&gt;

&lt;h2&gt;
  
  
  2 kinds of Store
&lt;/h2&gt;

&lt;p&gt;I assume that the one of the cause of fatness/complexity, in the large codebase between the UI components and the API access objects, is the mix of the 2 responsibilities in the name of Store.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The responsibility of external data access and caching

&lt;ul&gt;
&lt;li&gt;Accessing API to fetch data and holding it. The Repository.&lt;/li&gt;
&lt;li&gt;Its data will &lt;em&gt;not&lt;/em&gt; change unless executing write operations.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;The responsibility of storing UI states and managing them

&lt;ul&gt;
&lt;li&gt;A global store which its data keep over the page transition.&lt;/li&gt;
&lt;li&gt;Its data will change anytime by user's UI operation or some machine events.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, we assume there is a search page with "Search" button at the center and the facet view at the left, the store with the first responsibility should have the search condition data which indicates the current search result, and the one with the second responsibility should have the search condition draft which indicates the current UI state.&lt;/p&gt;

&lt;p&gt;I remember that the past configuration of Redux + async plugin combination usually tends to mix both of them in the same store/module. If they are separated into these reducers, it may be okay.&lt;/p&gt;

&lt;p&gt;From here, I call the store with the first &lt;br&gt;
 responsibility as &lt;strong&gt;Repository&lt;/strong&gt; and the another one as &lt;strong&gt;"UI Store"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;There are several technologies, of course, we just use them considering the kinds above. Though there is a right tech in the right place, I think we can choose them freely to the 2 kinds of "Store" (including the choise of the same tech).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hook based store

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;useState&lt;/code&gt; or &lt;code&gt;useReducer&lt;/code&gt; in the component&lt;/li&gt;
&lt;li&gt;Custome hook&lt;/li&gt;
&lt;li&gt;The global store with "constate" or self-made Redux-like store.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Redux

&lt;ul&gt;
&lt;li&gt;vanilla (plain)&lt;/li&gt;
&lt;li&gt;async plugin such as redux-thunk&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Data access class (including MobX)&lt;/li&gt;
&lt;li&gt;GraphQL library with caching feature&lt;/li&gt;
&lt;li&gt;Data resource of React Concurrent mode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example: Using a data resource of React Concurrent mode as the Repository and using a custome hook as the "UI Store".&lt;/p&gt;

&lt;h2&gt;
  
  
  Separate Presentation "System"&lt;sup id="fnref1"&gt;1&lt;/sup&gt;
&lt;/h2&gt;

&lt;p&gt;When the store layer becomes fat/complex and there are multiple different responsibilities, concerns, or systems in it, they should be separated; draw the dividing line between the Repository and the "UI Store". This is not a new idea. In the application server architecture, we usually follow the rule that separates the presentation layer (the view in MVC) from others. With the exception of the interface/contract, the Repository should not know what happens in the Presentation System, and vice versa.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aFG30zFG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7f9e79oo7p0erwkoih36.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aFG30zFG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7f9e79oo7p0erwkoih36.png" alt="about Presentation System"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;It does not mean better or not, but I just list up possible implementations&lt;sup id="fnref2"&gt;2&lt;/sup&gt;. In Pattern 1, "UI Store" is the bridge between the Repository and the Presentation System. In Pattern 2, the Container Component, and stateless hook called in it, combines the data flow from the Repository to the "UI Store".&lt;/p&gt;

&lt;p&gt;Though there are other perspectives of dividing codebase, I believe that only few methods conflict with this Presentation System separation. Of course it requires the kind of dependency injection to avoid the conflicts as usual. By separating the Presentation System as the first step, I believe, we can still easily separate the codebase with other perspective and the problem becomes smaller by removing the typical mix of the responsibility first.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Using reactive object such as Rx  &lt;/p&gt;

&lt;p&gt;Do it outside of the Presentation System. We should depend on the reactivity only provided by the view library (React, Vue, etc.) in the inside of the system.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Separating Command/Query like frontend CQRS&lt;/p&gt;

&lt;p&gt;Do it outside of the Presentation System. We should consider the data flow separately with Flux, in the system.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Concentric layered architecture&lt;sup id="fnref3"&gt;3&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Do it outside of the Presentation System. The presentation system corresponds to the outer layer(shell) since it is the &lt;em&gt;presentation&lt;/em&gt;&lt;sup id="fnref4"&gt;4&lt;/sup&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DDD in frontend&lt;/p&gt;

&lt;p&gt;Do it outside of the Presentation System. Maybe the system depends on either the primitive values or DDD domain models and/or usecases&lt;sup id="fnref5"&gt;5&lt;/sup&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Various component design patterns&lt;/p&gt;

&lt;p&gt;It should be closed in the Presentation System. I have not seen the component design pattern which crossing the system boundary.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Component library/framework&lt;/p&gt;

&lt;p&gt;It should be closed in the Presentation System.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;I described that we can divide the store into the 2 parts, the Repository and the "UI Store", and the codebase will be simpler if separating the Presentation System from others first.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;It's too large to call it as a "layer", so I call it as a "system". Moreover, just using presentation "layer" seems like that its target is only around the Presentational Component. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Initially I started writing this article with Pattern 1 in mind. However, I currently feel that Pattern 2 will be the mainline through the layer division of Container Component in the future. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;Such as Hexagonal Architecture, Clean Architecture, and Onion Architecture. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;I believe, however, the most important part is the Presentation System in frontend. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;To be honest, I do not have an experience of DDD in frontend. This is just a wild guess. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>frontend</category>
      <category>architecture</category>
      <category>codequality</category>
      <category>webdev</category>
    </item>
    <item>
      <title>View-Hook Pair Pattern (Draft)</title>
      <dc:creator>MasuqaT</dc:creator>
      <pubDate>Sat, 20 Feb 2021 03:06:11 +0000</pubDate>
      <link>https://dev.to/occar421/view-hook-pair-pattern-draft-5fjd</link>
      <guid>https://dev.to/occar421/view-hook-pair-pattern-draft-5fjd</guid>
      <description>&lt;p&gt;&lt;a href="https://blog.masuqat.net/2021/02/14/view-hook-pair-pattern-draft/"&gt;Japanese Version | 日本語版&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I recently "came up with" a new React design pattern. In this post, I just want to show you the method because it seems it will take a lot of time to write the whole background, problem and pros/cons.&lt;/p&gt;

&lt;p&gt;For the large chunk of the process, it is relatively "easy" to separate them by considering the layer and/or their concern. However, it is not easy for the frontend components due to other kinds of problem. I (roughly) "propose" a new divide-and-conquer pattern named "View-Hook Pair" to solve them.&lt;/p&gt;

&lt;h1&gt;
  
  
  Large Frontend Component
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QU_k0b3E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/kgolifww1wu8nfmv3mo3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QU_k0b3E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/kgolifww1wu8nfmv3mo3.png" alt="Image: SPA with many large components"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine the SPA app which has many large components; these components interact each other in the sense of the logic and UI. Whenever the user opens/closes &lt;code&gt;&amp;lt;ProjectPane /&amp;gt;&lt;/code&gt; tab, its content should be look the same. In other words, the internal UI state of &lt;code&gt;&amp;lt;ProjectPane /&amp;gt;&lt;/code&gt; should not be reset after its mounting and unmounting. To satisfy these UI requirements, we want to shape up the structure which the parent of &lt;code&gt;&amp;lt;ProjectPane /&amp;gt;&lt;/code&gt; have bare minimum of the control.&lt;/p&gt;

&lt;p&gt;Maybe we are going to achieve it by using Redux or some data store or by controlling all the states and logics (which ideally the parent should not concern) in the parent. It is difficult to separate them not just only styling the code but also improving the maintainability; loosely coupling and high cohesion.&lt;/p&gt;

&lt;h1&gt;
  
  
  View-Hook Pair Pattern
&lt;/h1&gt;

&lt;p&gt;For the problem, I "propose" a new divide-and-conquer pattern named "View-Hook Pair". As the name suggests, a pair is made by React JSX and React Hook. The former only controls UI code and latter only controls states and logics. Both may be exported and used from outside. I think this kind of pattern is used in the public already. I just reorganize them as a bit abstract pattern.&lt;/p&gt;

&lt;p&gt;Mainly a pair consists of items below. (The variable names in the example code has no special meaning.)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI code as View&lt;/li&gt;
&lt;li&gt;States &amp;amp; logics as Hook&lt;/li&gt;
&lt;li&gt;(if necessary) Integration code of the pair and/or Type definition of inter-pair-item interface &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It could be regarded as the gradual Model-View-ViewModel(MVVM) pattern using Hook.&lt;/p&gt;

&lt;h2&gt;
  
  
  View
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;disable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;PresentationModel&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;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;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&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="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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&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;enable&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Enable&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;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&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;disable&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Disable&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;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;div&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;In View item in the pair, it has all UI code in the component and written in a pure "state -&amp;gt; UI" function. It receives arguments from Hook result (in mind) and returns JSX.&lt;/p&gt;

&lt;p&gt;By separating the component to the UI code only chunk, it is easy to do unit tests and make visual catalog like Storybook story. In a naïve View, it contains the structure definition (HTML/XML) and the style definition (CSS). So we can separate View more to the layers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hook
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usePresentationModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({}:&lt;/span&gt; &lt;span class="nx"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;PresentationModel&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;enabled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setEnabled&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;false&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;enable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useCallback&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;setEnabled&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;disable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useCallback&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;setEnabled&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="c1"&gt;// other definitions...&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;enabled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;disable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Hook item in the pair, it has all the states and logics and written in a Custom Hook. It receives arguments of dependencies and/or initial values and returns values/callbacks to View in mind.&lt;/p&gt;

&lt;p&gt;By separating the component to states and logics only chunk, it is easy to do unit tests. When the hook gets fat, we can separate Hook to sub hooks by concerns like the method described in &lt;a href="https://kyleshevlin.com/use-encapsulation"&gt;useEncapsulation | Kyle Shevlin&lt;/a&gt; and/or putting a reducer or a data-access layer as plain "Model" (at least in the interface type) to the backward. Doing latter one, this Hook is regarded as "buffer zone" between React code and non-React code, like original MVVM ViewModel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic form of integration
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Container&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;presentationModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;usePresentationModel&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;presentationModel&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The basic form of the integration of the pair is just passing the Hook result to View. It can be okay to do integration test with it.&lt;/p&gt;

&lt;p&gt;The integration code should let pair-items concentrate on their concerns as much as possible.&lt;/p&gt;

&lt;h1&gt;
  
  
  Examples
&lt;/h1&gt;

&lt;p&gt;It is not easy to explain the merits with a small code example because this pattern is for the large components. Here, I will show the example utilizing this pattern inside of the component or outside of the component. (These are not limited to the page component.)&lt;/p&gt;

&lt;h2&gt;
  
  
  As testable separation for the component
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;changeTheme&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="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;initialize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;presentationModel&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;usePageLogics&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;changeTheme&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="nx"&gt;initialize&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PageView&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;presentationModel&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userName&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is possible to use a part of result from Hook in &lt;code&gt;useEffect&lt;/code&gt; to call some process after &lt;code&gt;Page&lt;/code&gt; mount (&lt;code&gt;initialize&lt;/code&gt; in the example). It is okay to mix Hook result values with props and/or context; values not from Hooks. (No overuse!)&lt;/p&gt;

&lt;p&gt;When to make more layers in &lt;code&gt;usePageLogics&lt;/code&gt;, do DI in &lt;code&gt;Page&lt;/code&gt; and avoid &lt;code&gt;usePageLogics&lt;/code&gt; depends directly on Context, Redux, Router or etc.&lt;/p&gt;

&lt;p&gt;As described above, we can test both pair-items and integration code easily.&lt;/p&gt;

&lt;p&gt;I reviewed and wrote a page component with this pattern in my work and the guy; who uses layered architecture in server side; said it is clear and easy to understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  As divide-and-conquer in the component
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Page&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isPaneOpen&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;false&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;projectListProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useProjectList&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;ProjectListContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&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;projectListProps&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;/* deep */
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isPaneOpen&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PaneContent&lt;/span&gt; &lt;span class="p"&gt;/&amp;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;
      /* deep */&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="nc"&gt;ProjectListContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  );
};

const PaneContent = () =&amp;gt; &lt;span class="si"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectListProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ProjectListContext&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProjectList&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;projectListProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem; the difference of the desired place for UI code and the desired place for the data lifecycle; is solved by separating the component to the pair and place pair-items separately. In the example above, the state of &lt;code&gt;&amp;lt;ProjectList /&amp;gt;&lt;/code&gt; will not change after toggling to &lt;code&gt;isPaneOpen === false&lt;/code&gt; condition. It is not necessary to prepare a global store and transform models only to achieve these requirements; keeping state and divide-and-conquer.&lt;/p&gt;

&lt;p&gt;Of cource, we can mix Hook result values with a local state or something in the place among &lt;code&gt;&amp;lt;Page /&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;LeftPane /&amp;gt;&lt;/code&gt;, so we can adjust values a bit easily. (In easy case, &lt;a href="https://github.com/jamiebuilds/unstated-next"&gt;Unstated Next&lt;/a&gt; is helpful.)&lt;/p&gt;

&lt;p&gt;Although View and Hook are placed separately in the parent component, we can do unit test and "integration test" by writing the integration code for the test.&lt;/p&gt;

&lt;p&gt;Unfortunately, it is still in experimental phase for me because some questions below perhaps indicate warning and a next evolutional pattern.&lt;/p&gt;

&lt;h1&gt;
  
  
  Current questions
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;(Like ViewModel in MVVM) The inter-pair-items interface type is exposed outside. This is good at adjusting but the same time, is it okay in sense of divide-and-conquer?&lt;/li&gt;
&lt;li&gt;If the component is enough small, the plain coupled form is easy and fast to implement. How to make a tradeoff?&lt;/li&gt;
&lt;li&gt;No example to split a large pair to the child pairs. Is it easy to split as same as a plain coupled component?&lt;/li&gt;
&lt;li&gt;Unknown potentials with using React Server Component. Is is still useful with it?&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>designpatterns</category>
      <category>codequality</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
