<?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: Crizant Lai</title>
    <description>The latest articles on DEV Community by Crizant Lai (@crizantl).</description>
    <link>https://dev.to/crizantl</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%2F345639%2F802445d5-62be-4d14-841d-85782bc38a7b.jpg</url>
      <title>DEV Community: Crizant Lai</title>
      <link>https://dev.to/crizantl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/crizantl"/>
    <language>en</language>
    <item>
      <title>Flutter: State management with ChangeNotifier</title>
      <dc:creator>Crizant Lai</dc:creator>
      <pubDate>Sun, 25 Jul 2021 10:23:14 +0000</pubDate>
      <link>https://dev.to/crizantl/flutter-state-management-with-changenotifier-3gjo</link>
      <guid>https://dev.to/crizantl/flutter-state-management-with-changenotifier-3gjo</guid>
      <description>&lt;p&gt;Tl;dr: Go visit &lt;a href="https://pub.dev/packages/change_notifier_builder"&gt;this package&lt;/a&gt; and see the example section.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is State Management?
&lt;/h2&gt;

&lt;p&gt;For those of you who are new to flutter: There should be no app which only display a single static screen, right? An app like this is no difference than an image. Every app should have certain parts of UIs which depends on some data, that data is called state. The process of structuring the state, and making the UI refreshes upon the change of the state is hence named state management.&lt;/p&gt;

&lt;h2&gt;
  
  
  State Management with &lt;code&gt;ChangeNotifier&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;In Flutter there are many ways to do state management. One of the ways is by using &lt;code&gt;ChangeNotifier&lt;/code&gt;. Comparing to the &lt;code&gt;setState&lt;/code&gt; method, using &lt;code&gt;ChangeNotifier&lt;/code&gt; lets you share the state among different widgets of your app, without having to worry about passing around the properties or “on change callbacks” by widget parameters.&lt;/p&gt;

&lt;p&gt;Let’s start by creating an instance of the model:&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;CounterModel&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;ChangeNotifier&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;increment&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_count&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
    &lt;span class="n"&gt;notifyListeners&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_count&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple enough. It has an integer &lt;code&gt;count&lt;/code&gt; value, and a method to increase the value by 1.&lt;/p&gt;

&lt;p&gt;Then we create an instance of the model somewhere:&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;final&lt;/span&gt; &lt;span class="n"&gt;CounterModel&lt;/span&gt; &lt;span class="n"&gt;counterModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CounterModel&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the UI. Here comes the real trick:&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;MyHomePage&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatelessWidget&lt;/span&gt; &lt;span class="o"&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="o"&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="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Scaffold&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;appBar:&lt;/span&gt; &lt;span class="n"&gt;AppBar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'My Home Page'&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
      &lt;span class="o"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;mainAxisAlignment:&lt;/span&gt; &lt;span class="n"&gt;MainAxisAlignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;center&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
          &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;[&lt;/span&gt;
            &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
              &lt;span class="s"&gt;'You have pushed the button this many times:'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="o"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;ChangeNotifierBuilder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
              &lt;span class="c1"&gt;// supply the instance of `ChangeNotifier` model,&lt;/span&gt;
              &lt;span class="c1"&gt;// whether you get it from the build context or anywhere&lt;/span&gt;
              &lt;span class="nl"&gt;notifier:&lt;/span&gt; &lt;span class="n"&gt;counterModel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
              &lt;span class="c1"&gt;// this builder function will be executed,&lt;/span&gt;
              &lt;span class="c1"&gt;// once the `ChangeNotifier` model is updated&lt;/span&gt;
              &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="o"&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="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CounterModel&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                  &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;${counter?.count ?? ''}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                  &lt;span class="nl"&gt;style:&lt;/span&gt; &lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;textTheme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;headline4&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="o"&gt;);&lt;/span&gt;
              &lt;span class="o"&gt;},&lt;/span&gt;
            &lt;span class="o"&gt;),&lt;/span&gt;
          &lt;span class="o"&gt;],&lt;/span&gt;
        &lt;span class="o"&gt;),&lt;/span&gt;
      &lt;span class="o"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;floatingActionButton:&lt;/span&gt; &lt;span class="n"&gt;FloatingActionButton&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="n"&gt;_counterModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;increment&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;tooltip:&lt;/span&gt; &lt;span class="s"&gt;'Increment'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
      &lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wrap the portion of your widget, which depends on the value of the model, in a &lt;code&gt;ChangeNotifierBuilder&lt;/code&gt;. The UI will be updated once the &lt;code&gt;notifyListener&lt;/code&gt;s method inside the model is invoked. The smaller the portion is, the faster the rebuild.&lt;/p&gt;




&lt;h2&gt;
  
  
  ChangeNotifierBuilder
&lt;/h2&gt;

&lt;p&gt;Wait. You said there is no such thing as &lt;code&gt;ChangeNotifierBuilder&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;You’re right! This is a &lt;a href="https://pub.dev/packages/change_notifier_builder"&gt;package created by me&lt;/a&gt;. Or you can use &lt;code&gt;AnimatedBuilder&lt;/code&gt; instead, they are pretty much the same thing.&lt;/p&gt;

&lt;p&gt;But I created the package for 3 reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;For the purpose of state management, &lt;code&gt;ChangeNotifierBuilder&lt;/code&gt; is a more reasonable and readable name than &lt;code&gt;AnimatedBuilder&lt;/code&gt;, for a builder widget.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sometimes our model is not yet ready (i.e. equals &lt;code&gt;null&lt;/code&gt;). In this case if you use &lt;code&gt;AnimatedBuilder&lt;/code&gt;, it throws "animation cannot be null" exception. However, if you use &lt;code&gt;ChangeNotifierBuilder&lt;/code&gt;, the runtime value of &lt;code&gt;notifier&lt;/code&gt; can be &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;builder&lt;/code&gt; method provides you the &lt;code&gt;T notifier&lt;/code&gt; object as a parameter, which is a bit more user-friendly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can’t listen to multiple &lt;code&gt;ChangeNotifier&lt;/code&gt;s with &lt;code&gt;AnimatedBuilder&lt;/code&gt;, so I created &lt;code&gt;MultiChangeNotifierBuilder&lt;/code&gt; for this purpose.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Optimizing Performance
&lt;/h2&gt;

&lt;p&gt;There are 3 techniques to boost performance when using &lt;code&gt;ChangeNotifierBuilder&lt;/code&gt; and &lt;code&gt;MultiChangeNotifierBuilder&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Never wrap the builder around the root of your widget tree.&lt;/strong&gt; Since we want to minimize the number of widgets to rebuild on every update, try wrapping the builder around the widgets which depend on the model only (&lt;strong&gt;the further away from the root the better&lt;/strong&gt;, i.e. the leaves).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the &lt;code&gt;builder&lt;/code&gt; callback’s return value contains a subtree that does not depend on the model, you may pass it as the &lt;code&gt;child&lt;/code&gt; parameter, instead of rebuilding it every time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t supply models which are not depended by the widget tree. Because unnecessary rebuilds will be triggered when those models update.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




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

&lt;p&gt;The final piece of the puzzle is, how do you pass the same instance of the model around your app?&lt;/p&gt;

&lt;p&gt;You can do it by creating a singleton model, or using the fantastic community packages like &lt;a href="https://pub.dev/packages/provider"&gt;provider&lt;/a&gt; or &lt;a href="https://pub.dev/packages/get_it"&gt;get_it&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>statemanagement</category>
      <category>dart</category>
    </item>
    <item>
      <title>Flutter: How to work with JSONs like a PRO</title>
      <dc:creator>Crizant Lai</dc:creator>
      <pubDate>Mon, 27 Apr 2020 12:56:34 +0000</pubDate>
      <link>https://dev.to/crizantl/flutter-how-to-work-with-jsons-like-a-pro-of0</link>
      <guid>https://dev.to/crizantl/flutter-how-to-work-with-jsons-like-a-pro-of0</guid>
      <description>&lt;p&gt;Before being a Flutter developer, I came from the JavaScript world. One thing I missed the most is the mighty JavaScript packages on &lt;a href="https://www.npmjs.com/"&gt;npm&lt;/a&gt;, especially &lt;a href="https://lodash.com/"&gt;lodash&lt;/a&gt; and &lt;a href="https://ramdajs.com/"&gt;ramda&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When developing Flutter applications, we often need to parse JSON objects from API responses, then access or manipulate them accordingly. Sadly dart language’s support for Map objects is not very rich, therefore I created this package: &lt;a href="https://pub.dev/packages/map_enhancer"&gt;map_enhancer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Usage&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:map_enhancer/map_enhancer.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Map&lt;/span&gt; &lt;span class="n"&gt;peter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="s"&gt;'firstName'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Peter'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="s"&gt;'lastName'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Petrelli'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;},&lt;/span&gt;
    &lt;span class="s"&gt;'age'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="o"&gt;};&lt;/span&gt;

  &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;peter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getIn&lt;/span&gt;&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'firstName'&lt;/span&gt;&lt;span class="o"&gt;]),&lt;/span&gt;
  &lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Output: Peter&lt;/span&gt;

  &lt;span class="c1"&gt;// or if you prefer the JSON "dot notation":&lt;/span&gt;
  &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;peter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getIn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'name.firstName'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;split&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'.'&lt;/span&gt;&lt;span class="o"&gt;)),&lt;/span&gt;
  &lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Output: Peter&lt;/span&gt;

  &lt;span class="c1"&gt;// call with default value:&lt;/span&gt;
  &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;peter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getIn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
      &lt;span class="s"&gt;'name.nickName'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;split&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'.'&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;defaultValue:&lt;/span&gt; &lt;span class="s"&gt;'Pete'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;),&lt;/span&gt;
  &lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Output: Pete&lt;/span&gt;

  &lt;span class="n"&gt;peter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setIn&lt;/span&gt;&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="s"&gt;'ability'&lt;/span&gt;&lt;span class="o"&gt;],&lt;/span&gt; &lt;span class="s"&gt;'Empathic mimicry'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;peter&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'ability'&lt;/span&gt;&lt;span class="o"&gt;]);&lt;/span&gt;
  &lt;span class="c1"&gt;// Output: Empathic mimicry&lt;/span&gt;

  &lt;span class="n"&gt;peter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unsetIn&lt;/span&gt;&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'lastName'&lt;/span&gt;&lt;span class="o"&gt;]);&lt;/span&gt;
  &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;peter&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="o"&gt;][&lt;/span&gt;&lt;span class="s"&gt;'lastName'&lt;/span&gt;&lt;span class="o"&gt;]);&lt;/span&gt;
  &lt;span class="c1"&gt;// Output: null&lt;/span&gt;

  &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;peter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasIn&lt;/span&gt;&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'nickname'&lt;/span&gt;&lt;span class="o"&gt;]));&lt;/span&gt;
  &lt;span class="c1"&gt;// Output: false&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Actually this package is not restricted to Flutter and JSON(Map) objects, you may use it in any dart projects, or on any dart’s native Map objects.&lt;/p&gt;

&lt;p&gt;And that’s it. Visit &lt;a href="https://pub.dev/packages/map_enhancer"&gt;pub.dev&lt;/a&gt; to install this package, or submit issues/pull requests on &lt;a href="https://github.com/crizant/dart_map_enhancer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>json</category>
    </item>
    <item>
      <title>Things you should consider before using DynamoDb</title>
      <dc:creator>Crizant Lai</dc:creator>
      <pubDate>Wed, 04 Mar 2020 09:35:30 +0000</pubDate>
      <link>https://dev.to/crizantl/things-you-should-consider-before-using-dynamodb-1c44</link>
      <guid>https://dev.to/crizantl/things-you-should-consider-before-using-dynamodb-1c44</guid>
      <description>&lt;p&gt;Lately, I'm been working on a project with DynamoDb, and this is my first time to meet this AWS service. It is just not a regular NoSQL database like &lt;code&gt;MongoDB&lt;/code&gt;, I have encountered a few issues (or features?) of it, I will share them along with the way I dealt with them(if I do know how to).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No empty strings&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;DynamoDB is a NoSQL database, but it cannot store empty strings. Not in any levels of your JSON object. If you have a single value which is an empty string in your object, DynamoDB throws an error.&lt;/p&gt;

&lt;p&gt;The workaround of this is, in &lt;code&gt;aws-sdk&lt;/code&gt; (for node developers like me, you can find it on &lt;code&gt;npm&lt;/code&gt;), it provides an option &lt;code&gt;convertEmptyValues&lt;/code&gt;, if you set it true, the empty strings will be converted to &lt;code&gt;null&lt;/code&gt; before being written into DB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Query operation size limit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;DynamoDB can maximum return 1MB of data in one query/scan operation. If your query contains more data, the results would include a key &lt;code&gt;last_evaluated_key&lt;/code&gt; that you need to include in the next query, in order to retrieve "next page" of data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Batch write limit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In every write requests, you can maximum include 25 rows only, which is very inconvenient. To deal with this issue and handle the possible write failure due to the exceed of throughput in concurrent write operations in multiple nodes, I have to do it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ramda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;batchWriteToDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dynamoDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DynamoDB&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;maxRetries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;999&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;docClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DynamoDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DocumentClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dynamoDb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;convertEmptyValues&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dataSegments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;splitEvery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// dynamoDb can only write 25 items once&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;dataSegments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;segment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dataSegments&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&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;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;RequestItems&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;tableName&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;PutRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}))&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;docClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;batchWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UnprocessedItems&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;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UnprocessedItems&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; unprocessed item(s) left, retrying...`&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;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;RequestItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UnprocessedItems&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;docClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;batchWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&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;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&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;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&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;Very clumsy, right?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Counting number of rows in a table&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In other databases, there should be simple APIs to count the number of rows in a table, but not in the case of DynamoDb. There are two ways to get the number of rows in a table:&lt;/p&gt;

&lt;p&gt;1. Use &lt;code&gt;DescribeTable&lt;/code&gt; API&lt;/p&gt;

&lt;p&gt;It returns information about a table, including the number of rows in it. But it only updates approximately every six hours, I think this is unacceptable.&lt;/p&gt;

&lt;p&gt;2. Do a full table scan&lt;/p&gt;

&lt;p&gt;Yet if your data exceeds 1MB, you have to do the scan operation recursively to get all pages of data…&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;DynamoDB is powerful, but it definitely got some trade-offs. If you come from the world of other NoSQL databases like &lt;code&gt;MongoDB&lt;/code&gt;, make sure you take the above points into consideration before switching.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>dynamodb</category>
      <category>nosql</category>
    </item>
  </channel>
</rss>
