<?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>Forem: Arnel Enero</title>
    <description>The latest articles on Forem by Arnel Enero (@arnelenero).</description>
    <link>https://forem.com/arnelenero</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%2F595821%2F0a3ca102-8e65-498e-8f02-89820335dd7a.png</url>
      <title>Forem: Arnel Enero</title>
      <link>https://forem.com/arnelenero</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/arnelenero"/>
    <language>en</language>
    <item>
      <title>Pitfalls of `process.env` every React developer should know</title>
      <dc:creator>Arnel Enero</dc:creator>
      <pubDate>Wed, 14 Sep 2022 08:32:37 +0000</pubDate>
      <link>https://forem.com/arnelenero/pitfalls-of-processenv-every-react-developer-should-know-18nh</link>
      <guid>https://forem.com/arnelenero/pitfalls-of-processenv-every-react-developer-should-know-18nh</guid>
      <description>&lt;h2&gt;
  
  
  Pitfall #1: It does not exist in the browser
&lt;/h2&gt;

&lt;p&gt;Unlike in Node.js, there is no such thing as &lt;code&gt;process.env&lt;/code&gt; object in the browser. One neat webpack trick, however, allows us to "emulate" this construct right in our React app. &lt;/p&gt;

&lt;p&gt;Webpack's &lt;code&gt;DefinePlugin&lt;/code&gt; injects environment variables by token replacement of &lt;code&gt;process.env.SOME_ENV_VAR&lt;/code&gt;. The final compiled JS will not have any reference to &lt;code&gt;process.env&lt;/code&gt; because, remember, it does not exist in the browser. So if we have something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SOME_ENV_VAR&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;webpack will compile that to something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value of SOME_ENV_VAR&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;h2&gt;
  
  
  Pitfall #2: We cannot assign values to it in React code
&lt;/h2&gt;

&lt;p&gt;This one is really just a natural side-effect of pitfall #1. Since &lt;code&gt;process.env&lt;/code&gt; will not exist in the compiled JS code, it follows that it doesn't make sense to try overriding environment variables inside our React app like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REACT_APP_ENV_VAR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cannot do this&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;h2&gt;
  
  
  Pitfall #3: It may get compiled in a way you didn't expect
&lt;/h2&gt;

&lt;p&gt;There is one significant pitfall that we need to be wary of: &lt;strong&gt;We need to make sure that all environment variables referenced in our source code are defined in our .env files or elsewhere.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;DefinePlugin&lt;/code&gt; cannot find a referenced env var's value, it will &lt;em&gt;not&lt;/em&gt; token-replace any references with &lt;code&gt;undefined&lt;/code&gt;. For example, if we have not defined REACT_APP_NOT_FOUND anywhere, but we have this code:&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REACT_APP_NOT_FOUND&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will &lt;em&gt;not&lt;/em&gt; translate to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead, webpack will string-replace just the &lt;code&gt;process.env&lt;/code&gt; part of the token with the &lt;strong&gt;entire key-value mapping of env vars&lt;/strong&gt;. So the translation is actually something like this (even after minification):&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;NODE_ENV&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;development&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;REACT_APP_NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;My&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;REACT_APP_ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="mi"&gt;232809283923&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="c1"&gt;// ... possibly a long list of other values&lt;/span&gt;
  &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nx"&gt;REACT_APP_NOT_FOUND&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now imagine if we have lots of checks like this throughout our code:&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REACT_APP_SOME_OPTIONAL_FLAG&lt;/span&gt;&lt;span class="p"&gt;)&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and we only define env vars in our .env file for flags that are true, thinking it’s fine because the logic above only cares about the &lt;em&gt;existence&lt;/em&gt; of the flag, not its value. &lt;/p&gt;

&lt;p&gt;But take the above compiled code containing the entire env vars object literal, and multiply it by who knows how many possibly-undefined env vars... for sure it’s going to hurt our bundle size.&lt;/p&gt;

&lt;p&gt;NOTE: The above behavior is based on how &lt;code&gt;process.env&lt;/code&gt; is &lt;em&gt;typically&lt;/em&gt; configured with &lt;code&gt;DefinePlugin&lt;/code&gt;, such as in Create React App. YMMV.&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Why explicit return type is a good thing</title>
      <dc:creator>Arnel Enero</dc:creator>
      <pubDate>Tue, 06 Sep 2022 07:06:48 +0000</pubDate>
      <link>https://forem.com/arnelenero/why-explicit-return-type-is-a-good-thing-43lj</link>
      <guid>https://forem.com/arnelenero/why-explicit-return-type-is-a-good-thing-43lj</guid>
      <description>&lt;p&gt;Back when I was just starting with TypeScript, I used to neglect the value of declaring an explicit return type for my functions. Why bother specifying it when there is type inference and IntelliSense, right? Well, I was very wrong.&lt;/p&gt;

&lt;p&gt;Turns out that its main benefit is actually &lt;em&gt;not&lt;/em&gt; to whomever might call my function, but rather to whomever might edit my function in the future. Here's why...&lt;/p&gt;

&lt;p&gt;Imagine I have this function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getAge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;calculateAge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;birthdate&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 is all good, as obviously it returns a &lt;code&gt;number&lt;/code&gt;, and IntelliSense tells me that, too. But then later on, someone edits my function to add a guard condition as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getAge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Person&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="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;birthdate&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;calculateAge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;birthdate&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 won't trigger a TS error at this function, but now the inferred return type has become &lt;code&gt;number | null&lt;/code&gt;, which is clearly different from the original intention. Now we have introduced, possibly unintentionally, a breaking change.&lt;/p&gt;

&lt;p&gt;Now imagine if I have specified a return type in the first place, as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getAge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// . . .&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then my team mate would have known from the start what can and can't be changed in the implementation without making a breaking change.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>JS Tidbit: A neat trick to compose arrays with conditional items using filter(Boolean)</title>
      <dc:creator>Arnel Enero</dc:creator>
      <pubDate>Sun, 31 Jul 2022 00:19:00 +0000</pubDate>
      <link>https://forem.com/arnelenero/js-tidbit-a-neat-trick-to-compose-arrays-with-conditional-items-using-filterboolean-2chn</link>
      <guid>https://forem.com/arnelenero/js-tidbit-a-neat-trick-to-compose-arrays-with-conditional-items-using-filterboolean-2chn</guid>
      <description>&lt;p&gt;Just a quick tip that you might find useful with JavaScript...&lt;/p&gt;

&lt;p&gt;When composing an array, we sometimes need to deal with items that are either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;potentially null or undefined, in which case we don't want to include it; or&lt;/li&gt;
&lt;li&gt;should only be included if a certain condition is satisfied&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a neat trick to do that cleanly:&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;list&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="s1"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;somethingThatCanBeNullOrUndefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;condition&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, &lt;code&gt;.filter(Boolean)&lt;/code&gt; will pass each array item to the &lt;code&gt;Boolean()&lt;/code&gt; constructor, which converts it to a boolean value (using JavaScript's truthy/falsy coercion). &lt;/p&gt;

&lt;p&gt;Therefore, if &lt;code&gt;somethingThatCanBeNullOrUndefined&lt;/code&gt; is null or undefined it becomes &lt;code&gt;false&lt;/code&gt; and hence excluded by the filter. Similarly, if &lt;code&gt;condition &amp;amp;&amp;amp; 'B'&lt;/code&gt; short-circuits to &lt;code&gt;false&lt;/code&gt; the item &lt;code&gt;'B'&lt;/code&gt; is excluded.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Turn a single brand color into your own Complete Web Color System... in minutes!</title>
      <dc:creator>Arnel Enero</dc:creator>
      <pubDate>Sun, 20 Mar 2022 22:03:36 +0000</pubDate>
      <link>https://forem.com/arnelenero/turn-a-single-brand-color-into-your-own-complete-web-color-system-in-minutes-4nkb</link>
      <guid>https://forem.com/arnelenero/turn-a-single-brand-color-into-your-own-complete-web-color-system-in-minutes-4nkb</guid>
      <description>&lt;p&gt;How many times have you neglected your app's UI just because you had a deadline, and you needed to focus on your app's functionality instead?&lt;/p&gt;

&lt;p&gt;Color forms an important foundation of every UI. It enables &lt;strong&gt;consistent&lt;/strong&gt; expression of your brand/identity and style, and &lt;strong&gt;effective&lt;/strong&gt; communication of intent and meaning.&lt;/p&gt;

&lt;p&gt;However, it can be quite daunting for developers like you and me to implement a proper color system, especially when this task has to contend with working on actual functionality of our app.&lt;/p&gt;

&lt;p&gt;For Web developers, here's where &lt;strong&gt;Simpler Color&lt;/strong&gt; could help. I wrote this small library so that we no longer have to sacrifice not having a cohesive, professional UI color system while focusing on the other important stuff. &lt;/p&gt;

&lt;p&gt;And all you need is &lt;strong&gt;a single brand color&lt;/strong&gt;...&lt;/p&gt;

&lt;h2&gt;
  
  
  Easy as 1-2-3
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; Install simpler-color&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install simpler-color
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Specify your brand color, and it generates the rest of the &lt;em&gt;base colors&lt;/em&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;harmony&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;simpler-color&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Generate 5 harmonious base colors from your main brand color!&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;baseColors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;harmony&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#609E3F&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;(You can also define your own custom base colors if you prefer, or if you already have a set of brand colors)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; Create your &lt;em&gt;color scheme(s)&lt;/em&gt; by mapping UI roles to specific colors from the auto-generated palettes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;colorScheme&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;simpler-color&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scheme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;colorScheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;baseColors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 👈 From these base colors...&lt;/span&gt;
  &lt;span class="c1"&gt;// 👇 ...your color palettes are auto-generated&lt;/span&gt;
  &lt;span class="nx"&gt;colors&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;// 👇 which you then map to UI roles.&lt;/span&gt;
    &lt;span class="na"&gt;primaryButton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;primaryButtonText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;95&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;surface&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;neutral&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;98&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;neutral&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;etc&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;// Access various UI colors as `scheme.primaryButton` and so on.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the complete range of colors that our example code generates from a single color value of &lt;code&gt;#609E3F&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9gNoev3---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/70fu1r0bkibr3f5vd2u4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9gNoev3---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/70fu1r0bkibr3f5vd2u4.png" alt="Example color set auto-generated by Simpler Color library" width="600" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's that simple! (Plus the library can do quite a bit more.)&lt;/p&gt;

&lt;p&gt;So why don't you give Simpler Color a try. Check it out on GitHub: &lt;a href="https://github.com/arnelenero/simpler-color"&gt;https://github.com/arnelenero/simpler-color&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please don't forget to give it a star ⭐️ on GitHub if you like the library, its concept and the simplicity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If some terms used above sound a bit alien to you, check out the comprehensive README in the link above for more details.&lt;/p&gt;

&lt;p&gt;Hope you find this library useful. With proper color, even an early prototype or proof-of-concept app would certainly impress!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Learn Navigator 2.0 by Building a Simpler API !</title>
      <dc:creator>Arnel Enero</dc:creator>
      <pubDate>Mon, 31 May 2021 14:06:03 +0000</pubDate>
      <link>https://forem.com/arnelenero/let-s-build-a-simpler-navigator-2-0-api-step-by-step-2emi</link>
      <guid>https://forem.com/arnelenero/let-s-build-a-simpler-navigator-2-0-api-step-by-step-2emi</guid>
      <description>&lt;p&gt;If you are reading this you probably have an opinion about Flutter's Navigator 2.0 being either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Too complicated, making it difficult to comprehend&lt;/li&gt;
&lt;li&gt;Too verbose, requiring a lot of boilerplate to do the job&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But despite this, it offers quite a number of features that were not possible with the simpler 1.0.&lt;/p&gt;

&lt;p&gt;Well, there's probably no better way to finally decipher Navigator 2.0 than to &lt;strong&gt;write our own simple wrapper API&lt;/strong&gt; on top of the beast. And we'll be solving 2 problems in one go!&lt;/p&gt;

&lt;p&gt;Don't worry, we will try to make sense of the whole thing, piece by piece, starting from the general concept down to the nitty gritty, and will be presented in the simplest way possible. &lt;/p&gt;

&lt;p&gt;So if you have some time, join me in this exciting challenge.  First up, let's give our library a name: ➡️ &lt;strong&gt;Flipbook&lt;/strong&gt; ⬅️.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;But hasn't the Flutter team already written a lengthy article explaining 2.0?&lt;/strong&gt; Yes, but I promise you we can do simpler than that approach. 🤓 &lt;/p&gt;
&lt;/blockquote&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note on 1.0&lt;/strong&gt;: If you have been writing Flutter apps for some time now, most likely you've already used the original Navigator 1.0. There are tons of materials on 1.0 online, so I won't waste your time on reviewing it here.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What Navigator 2.0 is for
&lt;/h2&gt;

&lt;p&gt;Let's forget about the whole thing about 2.0 being &lt;em&gt;declarative&lt;/em&gt; vs. &lt;em&gt;imperative&lt;/em&gt; first. If it didn't make it any simpler (many say it got much more complicated) then there is no point in talking too much about this aspect.&lt;/p&gt;

&lt;p&gt;Nav 2.0 works in a &lt;em&gt;reactive&lt;/em&gt; kind of way, much like how Flutter widgets work. So let's focus on 3 major things that 2.0 tries to achieve here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have the &lt;strong&gt;navigation&lt;/strong&gt; react to the &lt;strong&gt;app state&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Have the &lt;strong&gt;URL&lt;/strong&gt; update with the &lt;strong&gt;app state&lt;/strong&gt;. &lt;/li&gt;
&lt;li&gt;Have the &lt;strong&gt;app state&lt;/strong&gt; react to &lt;strong&gt;URL changes&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see above, 2.0 syncs up the navigation with the app state. And with Web now a first-class citizen in Flutter world, there is increased demand to sync the URL with the app, too.&lt;/p&gt;

&lt;p&gt;We'll dive into each one of those 3 areas as we look at how Nav 2.0 achieves those goals, and as we build out our simple API.&lt;/p&gt;

&lt;h2&gt;
  
  
  What our API should look like
&lt;/h2&gt;

&lt;p&gt;Let's ideate a little bit on how we want our Flipbook API to look from developer experience perspective.&lt;/p&gt;

&lt;p&gt;A drop-in replacement for &lt;code&gt;MaterialApp&lt;/code&gt; could be a good entry point because it immediately feels familiar. So here's a look at an example build method of a top-level App widget:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&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="n"&gt;Flipbook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;appName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;routes:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;'/login'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;LoginScreen&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="s"&gt;'*'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Shell&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;code&gt;Flipbook&lt;/code&gt; plays the role of a &lt;em&gt;router&lt;/em&gt;. The &lt;em&gt;routes&lt;/em&gt; are matched by &lt;em&gt;path&lt;/em&gt;, and are enumerated by top-to-bottom priority, with the last one typically being a wildcard to indicate "default" fallback.&lt;/p&gt;

&lt;p&gt;To switch screens, we just need to update the navigator state as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;route&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/login'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although this looks similar to the &lt;code&gt;pushNamed()&lt;/code&gt; approach from 1.0, here we no longer need to worry about calling &lt;code&gt;push&lt;/code&gt;, &lt;code&gt;pop&lt;/code&gt; or &lt;code&gt;replace&lt;/code&gt;. We just set the nav state to the correct path, and Flipbook should do the rest.&lt;/p&gt;

&lt;p&gt;Now that we have laid out the basic concept for our API, let's  start building...&lt;/p&gt;

&lt;h2&gt;
  
  
  Linking navigation to app state
&lt;/h2&gt;

&lt;p&gt;The main enabler for this functionality is the &lt;em&gt;router delegate&lt;/em&gt;, which is the mediator of all the pieces of our router (the &lt;code&gt;Flipbook&lt;/code&gt; widget). The &lt;code&gt;RouterDelegate&lt;/code&gt; class is the core of what Navigator 2.0 is all about, so let's carefully dissect this down to the essential pieces.&lt;/p&gt;

&lt;p&gt;We'll start by creating our subclass of the router delegate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FlippinRouterDelegate&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;RouterDelegate&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RoutePath&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;ChangeNotifier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 

  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;RouteMap&lt;/span&gt; &lt;span class="n"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;RouteState&lt;/span&gt; &lt;span class="n"&gt;routeState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RouteState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;GlobalKey&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;NavigatorState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;navigatorKey&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;FlippinRouterDelegate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;navigatorKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GlobalKey&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;NavigatorState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;routeState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;notifyListeners&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;So we can observe above that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The delegate has a &lt;code&gt;routes&lt;/code&gt; property which is the map of routes that we specify when we instantiate &lt;code&gt;Flipbook&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It has a &lt;code&gt;routeState&lt;/code&gt; property that stores the current route.&lt;/li&gt;
&lt;li&gt;It listens to changes in the &lt;code&gt;routeState&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It is also a &lt;code&gt;ChangeNotifier&lt;/code&gt;, so it can also relay the changes that it detects in &lt;code&gt;routeState&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The router delegate uses a generic type &lt;code&gt;&amp;lt;RoutePath&amp;gt;&lt;/code&gt; to indicate the data model it uses to represent route URLs internally. Since we like simplicity, here &lt;code&gt;RoutePath&lt;/code&gt; is just a type alias for &lt;code&gt;String&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The router delegate is responsible for building the &lt;em&gt;navigator&lt;/em&gt;, which controls the switching of our UI screens. So inside our delegate class, let's add this build method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&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="n"&gt;Navigator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;key:&lt;/span&gt; &lt;span class="n"&gt;navigatorKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;pages:&lt;/span&gt; &lt;span class="n"&gt;_getPages&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="nl"&gt;onPopPage:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;didPop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&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;Let's focus our attention on the &lt;code&gt;pages&lt;/code&gt; property for a bit. This is a list of &lt;em&gt;pages&lt;/em&gt; which represents the navigation history "stack". Initially the default screen is the only value in this list, then as you open screens on top of the last one (stack vs. replace), the additional screens are appended to the &lt;code&gt;pages&lt;/code&gt; list.&lt;/p&gt;

&lt;p&gt;So let's say you have a &lt;code&gt;MainScreen&lt;/code&gt; and from there you navigate to a &lt;code&gt;DetailScreen&lt;/code&gt; that opens on top of it, the &lt;code&gt;pages&lt;/code&gt; stack will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;      &lt;span class="nl"&gt;pages:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;MaterialPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;key:&lt;/span&gt; &lt;span class="n"&gt;ValueKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/main'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MainScreen&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="n"&gt;MaterialPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;key:&lt;/span&gt; &lt;span class="n"&gt;ValueKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/detail'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;DetailScreen&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
          &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our &lt;code&gt;_getPages()&lt;/code&gt; method will be responsible for dynamically generating this list based on the valid routes we specified when we instantiated &lt;code&gt;Flipbook&lt;/code&gt;, and the &lt;code&gt;Navigator&lt;/code&gt;'s state. &lt;/p&gt;

&lt;p&gt;Let's add our implementation of &lt;code&gt;_getPages()&lt;/code&gt;. Remember we're still on our router delegate class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="n"&gt;PageList&lt;/span&gt; &lt;span class="nf"&gt;_getPages&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;PageList&lt;/span&gt; &lt;span class="n"&gt;pages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;routes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;keys&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="n"&gt;_matchesRoutePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'*'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FadeAnimationPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;key:&lt;/span&gt; &lt;span class="n"&gt;ValueKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;routeState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="n"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&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="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;break&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="n"&gt;pages&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;_matchesRoutePath()&lt;/code&gt; function checks if the current route path matches one of those listed in the delegate's &lt;code&gt;routes&lt;/code&gt; property. I'll leave the implementation of this function to you, as it is pretty much an exercise of logic, rather than Nav 2.0.&lt;/p&gt;

&lt;p&gt;So we've covered the navigation part, and our router delegate class is &lt;em&gt;almost&lt;/em&gt; complete. Let's set it aside for a while and take care of the other important piece. &lt;/p&gt;

&lt;p&gt;At the other end of the link we're connecting is the part of the app state that, when updated, will trigger a navigation. Let's refer to this as the &lt;em&gt;route state&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Let's define our &lt;code&gt;RouteState&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RouteState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;ChangeNotifier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;PathParams&lt;/span&gt; &lt;span class="n"&gt;_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

  &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;newPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PathParams&lt;/span&gt; &lt;span class="n"&gt;newParams&lt;/span&gt; &lt;span class="o"&gt;=&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;newPath&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="n"&gt;_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newPath&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newParams&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;notifyListeners&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;RouteState&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RouteState&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;Notice that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;RouteState&lt;/code&gt; is also a &lt;code&gt;ChangeNotifier&lt;/code&gt;, so that the router delegate can listen to it.&lt;/li&gt;
&lt;li&gt;It has a &lt;code&gt;path&lt;/code&gt; property which stores the current URL of the current route&lt;/li&gt;
&lt;li&gt;It also has a &lt;code&gt;params&lt;/code&gt; property which is a map of URL parameters (if any). For example, if the route path looks something like &lt;code&gt;/items/:id&lt;/code&gt;, and the matched URL is &lt;code&gt;/items/1234&lt;/code&gt;, then our map will look like this: &lt;code&gt;{'id': '1234'}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Changes to these properties must be done by calling &lt;code&gt;setState()&lt;/code&gt; which notifies listeners of all such changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With that we've completed the connection between our navigator and the app state. Up next, we'll link up the app state to the route URL...&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating the URL when app state changes
&lt;/h2&gt;

&lt;p&gt;Although unnecessary most of the time, Nav 2.0 provides flexibility to "translate" URLs into a format that your app can use internally, sort of like a serialize/deserialize thing. It allows us to extend a &lt;code&gt;RouterInformationParser&lt;/code&gt; class for this purpose. (What a long name, I know! 😂)&lt;/p&gt;

&lt;p&gt;But for us who prefer simple solutions, let's just keep the URLs as plain strings, so here's our implementation of the parser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;typedef&lt;/span&gt; &lt;span class="n"&gt;RoutePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RouteParser&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;RouteInformationParser&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RoutePath&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RoutePath&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;parseRouteInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;RouteInformation&lt;/span&gt; &lt;span class="n"&gt;routeInformation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;routeInformation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;location&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;RouteInformation&lt;/span&gt; &lt;span class="n"&gt;restoreRouteInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RoutePath&lt;/span&gt; &lt;span class="n"&gt;data&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="n"&gt;RouteInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;location:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's just the same string value through and through. Nothing to see here.&lt;/p&gt;

&lt;p&gt;Now let's enable auto-updating our URL on every change to the pertinent app state (i.e. the &lt;code&gt;RouteState&lt;/code&gt;). Again it's our route delegate that will mediate the whole process. Here are the steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;listen for state change (✅ we already implemented this).&lt;/li&gt;
&lt;li&gt;Router delegate notifies our router (yes, &lt;code&gt;Flipbook&lt;/code&gt;) that the URL needs updating, then the router picks up the active route path from the delegate.&lt;/li&gt;
&lt;li&gt;The router uses the parser's &lt;code&gt;restoreRouteInformation&lt;/code&gt; to rewrap the URL in "route information" format. (✅ already covered above)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So what's still missing is the piece that handles that second step. Because we chose to use good ol' string format for route path, it's actually as simple as adding one line (a getter) to our &lt;code&gt;FlippinRouteDelegate&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="n"&gt;RoutePath&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;currentConfiguration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;routeState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one is called by the router (&lt;code&gt;Flipbook&lt;/code&gt;) to fetch the route path from the delegate.&lt;/p&gt;

&lt;p&gt;Now the inverse of this process: let's enable &lt;code&gt;RouteState&lt;/code&gt; to change whenever the URL changes (e.g. for Flutter Web, when user manually types a deep-linking URL)...&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating the app state when the URL changes
&lt;/h2&gt;

&lt;p&gt;This time here's what's happening:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The URL (manually) changes&lt;/li&gt;
&lt;li&gt;The router/&lt;code&gt;Flipbook&lt;/code&gt; uses the parser's &lt;code&gt;parseRouteInformation&lt;/code&gt; to translate the URL info.&lt;/li&gt;
&lt;li&gt;The router calls a method in the delegate to inform of this update. (👈 This is what we still need to add to our delegate class).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The method we're talking about is the &lt;code&gt;setNewRoutePath()&lt;/code&gt;. Let's add that to our &lt;code&gt;FlippinRouterDelegate&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;setNewRoutePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RoutePath&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;routeState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_getParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're done linking the URL to the app state. And with that, our &lt;code&gt;FlippinRouterDelegate&lt;/code&gt; implementation is now complete! Time to finally assemble our &lt;code&gt;Flipbook&lt;/code&gt; router widget...&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it all together
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're still with me, kudos for the patience and enthusiasm! Take a bathroom break or something. 🤣 This is the final stretch. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The last big piece of the puzzle is our &lt;code&gt;Flipbook&lt;/code&gt; widget. It makes use of everything we've built so far.&lt;/p&gt;

&lt;p&gt;Let's go straight to the code, looking at the widget class first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Flipbook&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatefulWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;ThemeData&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;RouteMap&lt;/span&gt; &lt;span class="n"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;Flipbook&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;_FlipbookState&lt;/span&gt; &lt;span class="n"&gt;createState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_FlipbookState&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 is a simplified version, but normally this should include all the properties of &lt;code&gt;MaterialApp&lt;/code&gt; that you need to define. Now on to the matching state class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;_FlipbookState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Flipbook&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;_routeParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RouteParser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;late&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;FlippinRouterDelegate&lt;/span&gt; &lt;span class="n"&gt;_routerDelegate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;initState&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="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;_routerDelegate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FlippinRouterDelegate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&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="n"&gt;MaterialApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;router&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;theme:&lt;/span&gt; &lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;routerDelegate:&lt;/span&gt; &lt;span class="n"&gt;_routerDelegate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;routeInformationParser:&lt;/span&gt; &lt;span class="n"&gt;_routeParser&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;Now one more little piece to complete the package. We need to create a &lt;code&gt;BuildContext&lt;/code&gt; extension so that widgets can easily update the route state, i.e. &lt;code&gt;context.route.setState(path)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;extension&lt;/span&gt; &lt;span class="n"&gt;RouteContext&lt;/span&gt; &lt;span class="kd"&gt;on&lt;/span&gt; &lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;RouteState&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;RouteState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&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;That's it. Congratulations for finishing this challenge with me!&lt;/p&gt;

&lt;h2&gt;
  
  
  Further exploration...
&lt;/h2&gt;

&lt;p&gt;We've built enough of our API to cover what we intended to build out, and hopefully it also gave us enough understanding of how Navigator 2.0 works.&lt;/p&gt;

&lt;p&gt;However there is always room for our API to grow, unfortunately we don't have time/space to cover everything here. These are some of the things that you may want to further pursue, for learning, utility or just having fun:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;nested routers &lt;/li&gt;
&lt;li&gt;handling of the Android Back button&lt;/li&gt;
&lt;li&gt;custom handling/animation of transitions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have implemented these already, but I'll let you take the challenge first, and then I'll post a gist on GitHub soon. 🤓&lt;/p&gt;

&lt;p&gt;Thank you for reading. I hope you gained something from this long journey.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>tutorial</category>
      <category>dart</category>
    </item>
    <item>
      <title>Can React state management get any simpler than this?</title>
      <dc:creator>Arnel Enero</dc:creator>
      <pubDate>Sun, 14 Mar 2021 19:08:27 +0000</pubDate>
      <link>https://forem.com/arnelenero/can-react-state-management-get-any-simpler-than-this-2o90</link>
      <guid>https://forem.com/arnelenero/can-react-state-management-get-any-simpler-than-this-2o90</guid>
      <description>&lt;p&gt;I'm one that loves simplicity in things. So despite the plethora of state management libraries for React, I have always wondered what the absolute "simplest" approach would be.&lt;/p&gt;

&lt;p&gt;After some time on the drawing board, &lt;em&gt;I think&lt;/em&gt; I've come up with just that. And today I'm happy to share with you &lt;strong&gt;SimpleR State&lt;/strong&gt;. (yes, with capital "R", for React 😂)&lt;/p&gt;

&lt;p&gt;Imagine being able to implement shared state in just 2 easy steps!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; Create an entity (shared state) and actions (updater functions)&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;entity&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;simpler-state&lt;/span&gt;&lt;span class="dl"&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;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;entity&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reset&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="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;increment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;by&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;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;by&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;Step 2:&lt;/strong&gt; Use the entity in your components with hooks&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reset&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CounterView&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;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;counter&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="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;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;count&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&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="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="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;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;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;reset&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; Reset &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;/&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;(Other components can use the shared &lt;code&gt;counter&lt;/code&gt; the same way.)&lt;/p&gt;

&lt;p&gt;It's that simple! &lt;strong&gt;But that's just a teaser, it can actually do a whole lot more!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here are some of the design goals for this library:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minimalist API&lt;/strong&gt;; no complicated concepts or boilerplate&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;plain functions&lt;/strong&gt; to implement state changes (including async)&lt;/li&gt;
&lt;li&gt;Largely &lt;strong&gt;unopinionated&lt;/strong&gt; with flexible syntax&lt;/li&gt;
&lt;li&gt;Extremely &lt;strong&gt;simple to unit test&lt;/strong&gt; state changes&lt;/li&gt;
&lt;li&gt;Highly extensible with &lt;strong&gt;plug-ins&lt;/strong&gt; (e.g. persistence, logging, dev tools)&lt;/li&gt;
&lt;li&gt;Full &lt;strong&gt;TypeScript&lt;/strong&gt; support with uncomplicated types&lt;/li&gt;
&lt;li&gt;Made specifically for React, and built on &lt;strong&gt;React Hooks&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;Multiple times &lt;strong&gt;faster&lt;/strong&gt; than context/reducer solution&lt;/li&gt;
&lt;li&gt;Tiny, just &lt;strong&gt;around 1 KB&lt;/strong&gt; (minified + gzipped)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If these benefits interest you, give SimpleR State a try. You can learn more about other things you can do with it at &lt;strong&gt;&lt;a href="https://simpler-state.js.org"&gt;simpler-state.js.org&lt;/a&gt;&lt;/strong&gt;. Yes, I wrote full documentation! 🤓&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And if you like this library, and/or the simplicity/concept behind it please give it a star on the &lt;a href="https://github.com/arnelenero/simpler-state"&gt;GitHub repo&lt;/a&gt; to let me know.&lt;/strong&gt; 😀👌&lt;/p&gt;

&lt;p&gt;So tell me, can the library get any simpler than this? I'd love to hear your suggestions. Goal is to get it closer to its bold claim of "simplest", &lt;strong&gt;not&lt;/strong&gt; to compete with other libraries as the "best".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I opened a Request For Comments (&lt;a href="https://github.com/arnelenero/simpler-state/issues/1"&gt;here&lt;/a&gt;) on GitHub. Your comments and suggestions would be greatly appreciated. Feel free to drop me a comment here 👇 too.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;blockquote&gt;
&lt;p&gt;Another P.S. -- I have prior art called &lt;code&gt;react-entities&lt;/code&gt; which has already been out for quite some time, and used by our company in production. SimpleR State is an evolution, based on the same stable core, but with completely different (much simpler) API.&lt;/p&gt;
&lt;/blockquote&gt;

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