<?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: Levi Zitting</title>
    <description>The latest articles on Forem by Levi Zitting (@levi_zitting).</description>
    <link>https://forem.com/levi_zitting</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%2F1207%2Ffec56016-03e3-4169-afaf-80aad9b55cf5.jpg</url>
      <title>Forem: Levi Zitting</title>
      <link>https://forem.com/levi_zitting</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/levi_zitting"/>
    <language>en</language>
    <item>
      <title>Flutter Multiple Stream Builder Package</title>
      <dc:creator>Levi Zitting</dc:creator>
      <pubDate>Sat, 19 Dec 2020 06:18:27 +0000</pubDate>
      <link>https://forem.com/levi_zitting/flutter-multiple-stream-builder-package-4l10</link>
      <guid>https://forem.com/levi_zitting/flutter-multiple-stream-builder-package-4l10</guid>
      <description>&lt;p&gt;When working with Flutter I find myself working with streams quite a bit. They're a great way to allow various parts of your app to be notified when data changes and keep things reactive.&lt;/p&gt;

&lt;p&gt;Flutter even provides a built-in widget for working with streams called &lt;code&gt;StreamBuilder&lt;/code&gt;. This widget allows you to pass in a stream along with a builder method that will get called every time the stream receives new data. Here's a quick example of how to use a StreamBuilder:&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;var&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;periodic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;seconds:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="nf"&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;StreamBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;stream:&lt;/span&gt; &lt;span class="n"&gt;stream&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="n"&gt;snapshot&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;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'value: &lt;/span&gt;&lt;span class="si"&gt;${snapshot.data}&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="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;For the most part, StreamBuilder works well. That is until you need values from multiple streams to build your UI. In that case, you have to resort to nesting StreamBuilders. Which, depending on how complicated your build method is can get a bit ugly.&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;var&lt;/span&gt; &lt;span class="n"&gt;stream1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;periodic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;seconds:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&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;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stream2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;periodic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;seconds:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&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;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stream3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;periodic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;seconds:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&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;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="nf"&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;StreamBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;stream:&lt;/span&gt; &lt;span class="n"&gt;stream1&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="n"&gt;snapshot1&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;StreamBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;stream:&lt;/span&gt; &lt;span class="n"&gt;stream2&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="n"&gt;snapshot2&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;StreamBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;stream:&lt;/span&gt; &lt;span class="n"&gt;stream3&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="n"&gt;snapshot3&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;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s"&gt;'stream1: &lt;/span&gt;&lt;span class="si"&gt;${snapshot1.data}&lt;/span&gt;&lt;span class="s"&gt; - stream2: &lt;/span&gt;&lt;span class="si"&gt;${snapshot2.data}&lt;/span&gt;&lt;span class="s"&gt; - stream3: &lt;/span&gt;&lt;span class="si"&gt;${snapshot3.data}&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="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="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 how can we clean this up? Let me introduce a package I published called &lt;a href="https://pub.dev/packages/multiple_stream_builder" rel="noopener noreferrer"&gt;&lt;code&gt;multiple_stream_builder&lt;/code&gt;&lt;/a&gt;. This package provides new widgets that behave almost the same as a normal StreamBuilder, but it allows you to pass in multiple streams instead of just one.&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;Widget&lt;/span&gt; &lt;span class="nf"&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;StreamBuilder3&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;streams:&lt;/span&gt; &lt;span class="n"&gt;StreamTuple3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stream2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stream3&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="n"&gt;snapshots&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;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;'stream1: &lt;/span&gt;&lt;span class="si"&gt;${snapshots.snapshot1.data}&lt;/span&gt;&lt;span class="s"&gt; - stream2: &lt;/span&gt;&lt;span class="si"&gt;${snapshots.snapshot2.data}&lt;/span&gt;&lt;span class="s"&gt; - stream3: &lt;/span&gt;&lt;span class="si"&gt;${snapshots.snapshot3.data}&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="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;As you can see this greatly shortens the amount of code we have to add as well as reduces the amount of nesting we need.&lt;br&gt;
Due to some &lt;a href="https://github.com/dart-lang/language/issues/363" rel="noopener noreferrer"&gt;technical limitations with the Dart language&lt;/a&gt; you have to use a different StreamBuilder depending on the number of streams you want to pass in. For example, if you need data from 4 streams you'd use &lt;code&gt;StreamBuilder4&lt;/code&gt; while you'd use &lt;code&gt;StreamBuilder2&lt;/code&gt; for 2 streams.&lt;/p&gt;

&lt;p&gt;If you want to get started using the package you can see the installation instructions on the &lt;a href="https://pub.dev/packages/multiple_stream_builder" rel="noopener noreferrer"&gt;package's pub.dev page&lt;/a&gt;. If you run into any issues with the package or would like to suggest a feature feel free to open an issue on the &lt;a href="https://github.com/glitchedmob/flutter_multiple_stream_builder" rel="noopener noreferrer"&gt;Github repo&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>mobile</category>
    </item>
    <item>
      <title>3 Features To Look For In a DNS Provider</title>
      <dc:creator>Levi Zitting</dc:creator>
      <pubDate>Thu, 20 Aug 2020 16:05:57 +0000</pubDate>
      <link>https://forem.com/levi_zitting/3-features-to-look-for-in-a-dns-provider-38bp</link>
      <guid>https://forem.com/levi_zitting/3-features-to-look-for-in-a-dns-provider-38bp</guid>
      <description>&lt;p&gt;There are countless DNS providers out there. Most of them make it easy enough to create and update the various records associated with your domains, but there are a handful of features that can make a DNS provider go from decent to amazing.&lt;/p&gt;

&lt;h4&gt;
  
  
  TTL Limit
&lt;/h4&gt;

&lt;p&gt;Most DNS providers give you the option to adjust the TTL your domains DNS record. This value tells other DNS servers how long to cache the record for. When changing the value of a record it can be handy to set the TTL to be very low sometime before adjusting the record's value so you see the change much faster. There are some DNS providers that won't let you set this value to be very low. For instance, Network Solution's lower limit for TTL values is one hour, which has caused me plenty of issues in the past trying to point records towards new resources. As a rule of thumb, 5 minutes as a lower limit is a good balance between the speed of changes and cacheability.&lt;/p&gt;

&lt;h4&gt;
  
  
  Web forwarding.
&lt;/h4&gt;

&lt;p&gt;There are plenty of scenarios where you may want to have traffic redirected from one domain or subdomain to another. (e.g &lt;a href="http://blog.mydomain.com/" rel="noopener noreferrer"&gt;blog.mydomain.com&lt;/a&gt; to &lt;a href="http://myotherdomain.com/blog" rel="noopener noreferrer"&gt;myotherdomain.com/blog&lt;/a&gt;). One way to handle this is to point the domain at a web server or web application and handle the redirect there. However the easiest way, if your DNS provider has the feature, is to use web forwarding. Most DNS providers that support web forwarding make it fairly simple, just choose the domain or subdomain you want to redirect and then choose the URL you want traffic to be directed to. This lets you avoid having to set up any additional redirects to handle simple redirects.&lt;/p&gt;

&lt;h4&gt;
  
  
  ALIAS, ANAME, Virtual CNAME records
&lt;/h4&gt;

&lt;p&gt;A tiny, annoying limitation in the DNS spec is that the &lt;a href="https://medium.freecodecamp.org/why-cant-a-domain-s-root-be-a-cname-8cbab38e5f5c" rel="noopener noreferrer"&gt;root record for a domain can't be a CNAME&lt;/a&gt;. This can be incredibly frustrating when trying to point a record towards a resource such as an AWS Application Load Balancer. Resources like these don't always provide an actual IP for an A record to use, instead, they usually provide some other DNS name and expect you to create a CNAME record to direct traffic at the resource. Due to this DNS limitation, you would have to have traffic go through a subdomain (such as www) and have traffic to the root domain be redirected to the subdomain. (using something like web forwarding or a redirect server with a static IP)&lt;br&gt;
However, some DNS providers offer workarounds to this DNS limitation through nonstandard record types. The most popular of these are ALIAS, ANAME, or Virtual CNAME records. These records are used exactly like traditional CNAME records. Behind the scenes, the DNS provider will resolve the record's value to the actual IPs and present them to the outside world as A records.&lt;/p&gt;

</description>
      <category>dns</category>
      <category>webdev</category>
      <category>devops</category>
    </item>
    <item>
      <title>Hi, I'm Levi Zitting</title>
      <dc:creator>Levi Zitting</dc:creator>
      <pubDate>Tue, 07 Feb 2017 20:02:04 +0000</pubDate>
      <link>https://forem.com/levi_zitting/hi-im-levi-zitting</link>
      <guid>https://forem.com/levi_zitting/hi-im-levi-zitting</guid>
      <description>&lt;p&gt;I have been coding for 5+ years. I'm 19 years old and I live in southwest MO&lt;/p&gt;

&lt;p&gt;You can find me on Twitter as &lt;a href="https://twitter.com/levi_zitting" rel="noopener noreferrer"&gt;@levi_zitting&lt;/a&gt; and on Github as &lt;a href="https://github.com/glitchedmob" rel="noopener noreferrer"&gt;@glitchedmob&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I work with JavaScript, TypeScript, and PHP&lt;/p&gt;

</description>
      <category>introduction</category>
    </item>
  </channel>
</rss>
