<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Minimal Blog - @lekoarts/gatsby-theme-minimal-blog]]></title><description><![CDATA[Minimal Blog - @lekoarts/gatsby-theme-minimal-blog]]></description><link>https://minimal-blog.lekoarts.de</link><generator>GatsbyJS</generator><lastBuildDate>Mon, 03 Aug 2020 18:58:20 GMT</lastBuildDate><item><title><![CDATA[Build an iTunes Search App with SwiftUI and The Composable Architecture [Part 1]]]></title><link>https://minimal-blog.lekoarts.de/blog/build-an-itunes-search-app-with-swiftui-and-the-composable-architecture-part-1</link><guid isPermaLink="false">https://minimal-blog.lekoarts.de/blog/build-an-itunes-search-app-with-swiftui-and-the-composable-architecture-part-1</guid><pubDate>Sun, 14 Jun 2020 07:00:00 GMT</pubDate><content:encoded>&lt;style data-emotion-css=&quot;1hycliv&quot;&gt;body{--theme-ui-colors-transparent:var(--theme-ui-colors-transparent,transparent);--theme-ui-colors-black:var(--theme-ui-colors-black,#000);--theme-ui-colors-white:var(--theme-ui-colors-white,#fff);--theme-ui-colors-gray-0:var(--theme-ui-colors-gray-0,null);--theme-ui-colors-gray-1:var(--theme-ui-colors-gray-1,#f7fafc);--theme-ui-colors-gray-2:var(--theme-ui-colors-gray-2,#edf2f7);--theme-ui-colors-gray-3:var(--theme-ui-colors-gray-3,#e2e8f0);--theme-ui-colors-gray-4:var(--theme-ui-colors-gray-4,#cbd5e0);--theme-ui-colors-gray-5:var(--theme-ui-colors-gray-5,#a0aec0);--theme-ui-colors-gray-6:var(--theme-ui-colors-gray-6,#718096);--theme-ui-colors-gray-7:var(--theme-ui-colors-gray-7,#4a5568);--theme-ui-colors-gray-8:var(--theme-ui-colors-gray-8,#2d3748);--theme-ui-colors-gray-9:var(--theme-ui-colors-gray-9,#1a202c);--theme-ui-colors-red-0:var(--theme-ui-colors-red-0,null);--theme-ui-colors-red-1:var(--theme-ui-colors-red-1,#fff5f5);--theme-ui-colors-red-2:var(--theme-ui-colors-red-2,#fed7d7);--theme-ui-colors-red-3:var(--theme-ui-colors-red-3,#feb2b2);--theme-ui-colors-red-4:var(--theme-ui-colors-red-4,#fc8181);--theme-ui-colors-red-5:var(--theme-ui-colors-red-5,#f56565);--theme-ui-colors-red-6:var(--theme-ui-colors-red-6,#e53e3e);--theme-ui-colors-red-7:var(--theme-ui-colors-red-7,#c53030);--theme-ui-colors-red-8:var(--theme-ui-colors-red-8,#9b2c2c);--theme-ui-colors-red-9:var(--theme-ui-colors-red-9,#742a2a);--theme-ui-colors-orange-0:var(--theme-ui-colors-orange-0,null);--theme-ui-colors-orange-1:var(--theme-ui-colors-orange-1,#fffaf0);--theme-ui-colors-orange-2:var(--theme-ui-colors-orange-2,#feebc8);--theme-ui-colors-orange-3:var(--theme-ui-colors-orange-3,#fbd38d);--theme-ui-colors-orange-4:var(--theme-ui-colors-orange-4,#f6ad55);--theme-ui-colors-orange-5:var(--theme-ui-colors-orange-5,#ed8936);--theme-ui-colors-orange-6:var(--theme-ui-colors-orange-6,#dd6b20);--theme-ui-colors-orange-7:var(--theme-ui-colors-orange-7,#c05621);--theme-ui-colors-orange-8:var(--theme-ui-colors-orange-8,#9c4221);--theme-ui-colors-orange-9:var(--theme-ui-colors-orange-9,#7b341e);--theme-ui-colors-yellow-0:var(--theme-ui-colors-yellow-0,null);--theme-ui-colors-yellow-1:var(--theme-ui-colors-yellow-1,#fffff0);--theme-ui-colors-yellow-2:var(--theme-ui-colors-yellow-2,#fefcbf);--theme-ui-colors-yellow-3:var(--theme-ui-colors-yellow-3,#faf089);--theme-ui-colors-yellow-4:var(--theme-ui-colors-yellow-4,#f6e05e);--theme-ui-colors-yellow-5:var(--theme-ui-colors-yellow-5,#ecc94b);--theme-ui-colors-yellow-6:var(--theme-ui-colors-yellow-6,#d69e2e);--theme-ui-colors-yellow-7:var(--theme-ui-colors-yellow-7,#b7791f);--theme-ui-colors-yellow-8:var(--theme-ui-colors-yellow-8,#975a16);--theme-ui-colors-yellow-9:var(--theme-ui-colors-yellow-9,#744210);--theme-ui-colors-green-0:var(--theme-ui-colors-green-0,null);--theme-ui-colors-green-1:var(--theme-ui-colors-green-1,#f0fff4);--theme-ui-colors-green-2:var(--theme-ui-colors-green-2,#c6f6d5);--theme-ui-colors-green-3:var(--theme-ui-colors-green-3,#9ae6b4);--theme-ui-colors-green-4:var(--theme-ui-colors-green-4,#68d391);--theme-ui-colors-green-5:var(--theme-ui-colors-green-5,#48bb78);--theme-ui-colors-green-6:var(--theme-ui-colors-green-6,#38a169);--theme-ui-colors-green-7:var(--theme-ui-colors-green-7,#2f855a);--theme-ui-colors-green-8:var(--theme-ui-colors-green-8,#276749);--theme-ui-colors-green-9:var(--theme-ui-colors-green-9,#22543d);--theme-ui-colors-teal-0:var(--theme-ui-colors-teal-0,null);--theme-ui-colors-teal-1:var(--theme-ui-colors-teal-1,#e6fffa);--theme-ui-colors-teal-2:var(--theme-ui-colors-teal-2,#b2f5ea);--theme-ui-colors-teal-3:var(--theme-ui-colors-teal-3,#81e6d9);--theme-ui-colors-teal-4:var(--theme-ui-colors-teal-4,#4fd1c5);--theme-ui-colors-teal-5:var(--theme-ui-colors-teal-5,#38b2ac);--theme-ui-colors-teal-6:var(--theme-ui-colors-teal-6,#319795);--theme-ui-colors-teal-7:var(--theme-ui-colors-teal-7,#2c7a7b);--theme-ui-colors-teal-8:var(--theme-ui-colors-teal-8,#285e61);--theme-ui-colors-teal-9:var(--theme-ui-colors-teal-9,#234e52);--theme-ui-colors-blue-0:var(--theme-ui-colors-blue-0,null);--theme-ui-colors-blue-1:var(--theme-ui-colors-blue-1,#ebf8ff);--theme-ui-colors-blue-2:var(--theme-ui-colors-blue-2,#bee3f8);--theme-ui-colors-blue-3:var(--theme-ui-colors-blue-3,#90cdf4);--theme-ui-colors-blue-4:var(--theme-ui-colors-blue-4,#63b3ed);--theme-ui-colors-blue-5:var(--theme-ui-colors-blue-5,#4299e1);--theme-ui-colors-blue-6:var(--theme-ui-colors-blue-6,#3182ce);--theme-ui-colors-blue-7:var(--theme-ui-colors-blue-7,#2b6cb0);--theme-ui-colors-blue-8:var(--theme-ui-colors-blue-8,#2c5282);--theme-ui-colors-blue-9:var(--theme-ui-colors-blue-9,#2a4365);--theme-ui-colors-indigo-0:var(--theme-ui-colors-indigo-0,null);--theme-ui-colors-indigo-1:var(--theme-ui-colors-indigo-1,#ebf4ff);--theme-ui-colors-indigo-2:var(--theme-ui-colors-indigo-2,#c3dafe);--theme-ui-colors-indigo-3:var(--theme-ui-colors-indigo-3,#a3bffa);--theme-ui-colors-indigo-4:var(--theme-ui-colors-indigo-4,#7f9cf5);--theme-ui-colors-indigo-5:var(--theme-ui-colors-indigo-5,#667eea);--theme-ui-colors-indigo-6:var(--theme-ui-colors-indigo-6,#5a67d8);--theme-ui-colors-indigo-7:var(--theme-ui-colors-indigo-7,#4c51bf);--theme-ui-colors-indigo-8:var(--theme-ui-colors-indigo-8,#434190);--theme-ui-colors-indigo-9:var(--theme-ui-colors-indigo-9,#3c366b);--theme-ui-colors-purple-0:var(--theme-ui-colors-purple-0,null);--theme-ui-colors-purple-1:var(--theme-ui-colors-purple-1,#faf5ff);--theme-ui-colors-purple-2:var(--theme-ui-colors-purple-2,#e9d8fd);--theme-ui-colors-purple-3:var(--theme-ui-colors-purple-3,#d6bcfa);--theme-ui-colors-purple-4:var(--theme-ui-colors-purple-4,#b794f4);--theme-ui-colors-purple-5:var(--theme-ui-colors-purple-5,#9f7aea);--theme-ui-colors-purple-6:var(--theme-ui-colors-purple-6,#805ad5);--theme-ui-colors-purple-7:var(--theme-ui-colors-purple-7,#6b46c1);--theme-ui-colors-purple-8:var(--theme-ui-colors-purple-8,#553c9a);--theme-ui-colors-purple-9:var(--theme-ui-colors-purple-9,#44337a);--theme-ui-colors-pink-0:var(--theme-ui-colors-pink-0,null);--theme-ui-colors-pink-1:var(--theme-ui-colors-pink-1,#fff5f7);--theme-ui-colors-pink-2:var(--theme-ui-colors-pink-2,#fed7e2);--theme-ui-colors-pink-3:var(--theme-ui-colors-pink-3,#fbb6ce);--theme-ui-colors-pink-4:var(--theme-ui-colors-pink-4,#f687b3);--theme-ui-colors-pink-5:var(--theme-ui-colors-pink-5,#ed64a6);--theme-ui-colors-pink-6:var(--theme-ui-colors-pink-6,#d53f8c);--theme-ui-colors-pink-7:var(--theme-ui-colors-pink-7,#b83280);--theme-ui-colors-pink-8:var(--theme-ui-colors-pink-8,#97266d);--theme-ui-colors-pink-9:var(--theme-ui-colors-pink-9,#702459);--theme-ui-colors-grayDark:var(--theme-ui-colors-grayDark,#2d3748);--theme-ui-colors-text:var(--theme-ui-colors-text,#2d3748);--theme-ui-colors-background:var(--theme-ui-colors-background,#fff);--theme-ui-colors-primary:var(--theme-ui-colors-primary,#6b46c1);--theme-ui-colors-primaryHover:var(--theme-ui-colors-primaryHover,#2c5282);--theme-ui-colors-secondary:var(--theme-ui-colors-secondary,#5f6c80);--theme-ui-colors-muted:var(--theme-ui-colors-muted,#e2e8f0);--theme-ui-colors-success:var(--theme-ui-colors-success,#9ae6b4);--theme-ui-colors-info:var(--theme-ui-colors-info,#63b3ed);--theme-ui-colors-warning:var(--theme-ui-colors-warning,#faf089);--theme-ui-colors-danger:var(--theme-ui-colors-danger,#feb2b2);--theme-ui-colors-light:var(--theme-ui-colors-light,#f7fafc);--theme-ui-colors-dark:var(--theme-ui-colors-dark,#2d3748);--theme-ui-colors-textMuted:var(--theme-ui-colors-textMuted,#718096);--theme-ui-colors-toggleIcon:var(--theme-ui-colors-toggleIcon,#2d3748);--theme-ui-colors-heading:var(--theme-ui-colors-heading,#000);--theme-ui-colors-divide:var(--theme-ui-colors-divide,#cbd5e0);color:var(--theme-ui-colors-text,#2d3748);background-color:var(--theme-ui-colors-background,#fff);}body.theme-ui-dark{--theme-ui-colors-text:var(--theme-ui-colors-modes-dark-text,#cbd5e0);--theme-ui-colors-primary:var(--theme-ui-colors-modes-dark-primary,#9f7aea);--theme-ui-colors-secondary:var(--theme-ui-colors-modes-dark-secondary,#7f8ea3);--theme-ui-colors-toggleIcon:var(--theme-ui-colors-modes-dark-toggleIcon,#cbd5e0);--theme-ui-colors-background:var(--theme-ui-colors-modes-dark-background,#1A202C);--theme-ui-colors-heading:var(--theme-ui-colors-modes-dark-heading,#fff);--theme-ui-colors-divide:var(--theme-ui-colors-modes-dark-divide,#2d3748);--theme-ui-colors-muted:var(--theme-ui-colors-modes-dark-muted,#2d3748);}&lt;/style&gt;&lt;style data-emotion-css=&quot;15y10hy&quot;&gt;*{box-sizing:border-box;}body{margin:0;font-family:&quot;IBM Plex Sans&quot;,-apple-system,BlinkMacSystemFont,&quot;Segoe UI&quot;,Roboto,&quot;Helvetica Neue&quot;,Arial,&quot;Noto Sans&quot;,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;,&quot;Segoe UI Symbol&quot;,&quot;Noto Color Emoji&quot;;line-height:1.625;font-weight:400;color:var(--theme-ui-colors-text,#2d3748);background-color:var(--theme-ui-colors-background,#fff);padding:0;box-sizing:border-box;text-rendering:optimizeLegibility;}&lt;/style&gt;&lt;style data-emotion-css=&quot;1bkk5q4&quot;&gt;.css-1bkk5q4{font-size:1rem;-webkit-letter-spacing:-0.003em;-moz-letter-spacing:-0.003em;-ms-letter-spacing:-0.003em;letter-spacing:-0.003em;line-height:1.625;--baseline-multiplier:0.179;--x-height-multiplier:0.35;}@media screen and (min-width:640px){.css-1bkk5q4{font-size:1rem;}}@media screen and (min-width:768px){.css-1bkk5q4{font-size:1.25rem;}}&lt;/style&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;&lt;code class=&quot;css-0&quot;&gt;Version: Swift 5, iOS 13, Xcode 11, The Composable Architecture 0.3.0&lt;/code&gt;&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1592176079987/2arp2Mvqc.jpeg&quot; alt=&quot;TCA.jpg&quot; class=&quot;css-0&quot;/&gt;&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;The Composable Architecture (TCA) by &lt;style data-emotion-css=&quot;1od09yo&quot;&gt;.css-1od09yo{color:var(--theme-ui-colors-primary,#6b46c1);-webkit-text-decoration:none;text-decoration:none;}.css-1od09yo:hover{-webkit-text-decoration:underline;text-decoration:underline;}&lt;/style&gt;&lt;a href=&quot;https://www.pointfree.co&quot; class=&quot;css-1od09yo&quot;&gt;Point-Free&lt;/a&gt; is a Swift library for application state management that draws inspiration from libraries like Elm and Redux. It pairs very well with SwiftUI&amp;#x27;s declarative nature.&lt;/p&gt;&lt;style data-emotion-css=&quot;1bzbprl&quot;&gt;.css-1bzbprl{font-family:inherit;font-weight:700;line-height:1.25;margin:0;margin-bottom:0.25rem;font-size:1.875rem;margin-top:0.5rem;color:var(--theme-ui-colors-heading,#000);}@media screen and (min-width:640px){.css-1bzbprl{font-size:2.25rem;}}@media screen and (min-width:768px){.css-1bzbprl{font-size:3rem;}}&lt;/style&gt;&lt;h2 class=&quot;css-1bzbprl&quot;&gt;What We&amp;#x27;re Building&lt;/h2&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;In this tutorial, we&amp;#x27;ll explore the concepts of TCA and use that them to build an application that will take in user input, call the iTunes API with that query, and return a list of artist results. We&amp;#x27;ll render that list and users will be able to click on an artist in that list to go to their Apple Music page inside of a custom web view.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1592170754195/ipVwamRYX.gif&quot; alt=&quot;itunes_kota2.gif&quot; class=&quot;css-0&quot;/&gt;&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;The focus on this tutorial is to cover TCA, so we won&amp;#x27;t cover basic SwiftUI concepts here. There are already a lot of great resources cover SwiftUI including &lt;a href=&quot;https://developer.apple.com/tutorials/swiftui/&quot; class=&quot;css-1od09yo&quot;&gt;Apple&amp;#x27;s SwiftUI tutorial&lt;/a&gt;.&lt;/p&gt;&lt;h2 class=&quot;css-1bzbprl&quot;&gt;Getting Started with Swift Package Manager&lt;/h2&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;Let&amp;#x27;s start off by creating a new Single View App SwiftUI project in Xcode.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;To add TCA as a Swift Package, go to &lt;code class=&quot;css-0&quot;&gt;File&lt;/code&gt; &amp;gt; &lt;code class=&quot;css-0&quot;&gt;Swift Packages&lt;/code&gt; &amp;gt; &lt;code class=&quot;css-0&quot;&gt;Add Package Dependency&lt;/code&gt; and paste in the &lt;a href=&quot;https://github.com/pointfreeco/swift-composable-architecture&quot; class=&quot;css-1od09yo&quot;&gt;GitHub url&lt;/a&gt; for TCA when prompted.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1592088938699/C7-9VYh-W.png&quot; alt=&quot;Screen Shot 2020-06-13 at 3.55.02 PM.png&quot; class=&quot;css-0&quot;/&gt;&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;Select your preferred rules, or just press &lt;code class=&quot;css-0&quot;&gt;Next&lt;/code&gt; to lock in any package updates up until the next major release. &lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1592089105616/vb7pWfk_p.png&quot; alt=&quot;Screen Shot 2020-06-13 at 3.57.54 PM.png&quot; class=&quot;css-0&quot;/&gt;&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;For this project, we&amp;#x27;ll only need TCA&amp;#x27;s core library. We won&amp;#x27;t be using Core Location.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1592089116891/ac66iETKVA.png&quot; alt=&quot;Screen Shot 2020-06-13 at 3.58.06 PM.png&quot; class=&quot;css-0&quot;/&gt;&lt;/p&gt;&lt;h2 class=&quot;css-1bzbprl&quot;&gt;Creating the Root State, Action, Environment, and Reducer&lt;/h2&gt;&lt;style data-emotion-css=&quot;1gtwvjp&quot;&gt;.css-1gtwvjp{border-left-color:var(--theme-ui-colors-primary,#6b46c1);border-left-style:solid;border-left-width:6px;margin-left:0;margin-right:0;padding-left:2rem;}.css-1gtwvjp p{font-style:italic;}&lt;/style&gt;&lt;blockquote class=&quot;css-1gtwvjp&quot;&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;State&lt;/p&gt;&lt;/blockquote&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;The root &lt;code class=&quot;css-0&quot;&gt;state&lt;/code&gt; holds the entire state of our application. It lives inside of the &lt;code class=&quot;css-0&quot;&gt;store&lt;/code&gt; and can be expressed as a tree structure. Any data that we want to observe should live as a property in state.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;It&amp;#x27;s good practice to break down the root-level state into smaller pieces of state based on views, screens, or features. &lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;Passing the entire application state to each view is an anti-pattern and goes against the principles of this architecture. We want to make sure that the components of this application don&amp;#x27;t have too much knowledge of what lives outside itself. &lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;&lt;code class=&quot;css-0&quot;&gt;State&lt;/code&gt; in TCA is implemented as a struct. It must conform to &lt;code class=&quot;css-0&quot;&gt;Equatable&lt;/code&gt; so that TCA knows how to deduplicate state updates under the hood. &lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;The first property we&amp;#x27;ll track in our state is our current search query. For now, it will live in the root state of the application, but we will eventually pull it out into one of our child states.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1592092275891/LALZekZUK.png&quot; alt=&quot;Screen Shot 2020-06-13 at 4.51.05 PM.png&quot; class=&quot;css-0&quot;/&gt;&lt;/p&gt;&lt;blockquote class=&quot;css-1gtwvjp&quot;&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;Action&lt;/p&gt;&lt;/blockquote&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;An &lt;code class=&quot;css-0&quot;&gt;action&lt;/code&gt; describes an event that is going to happen inside of an application. &lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;TCA enforces the concept of immutable state by requiring an action to be dispatched to a &lt;code class=&quot;css-0&quot;&gt;reducer&lt;/code&gt; in order to update state. State can&amp;#x27;t be written to directly by design.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;It should be noted that all state changes need to be expressed with actions, but not all actions need to trigger state changes. Actions can also be used to trigger side effects including dispatching another action or making a network request.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;Similar to state, actions must conform to &lt;code class=&quot;css-0&quot;&gt;Equatable&lt;/code&gt;. We can optionally send an associated value with our action. This is necessary if the reducer needs that value in order to update state or pass along to an environment.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;In this tutorial, our first action will describe how we&amp;#x27;re updating our iTunes artist search query.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1592092661555/eHr1cCnGl.png&quot; alt=&quot;Screen Shot 2020-06-13 at 4.57.26 PM.png&quot; class=&quot;css-0&quot;/&gt;&lt;/p&gt;&lt;blockquote class=&quot;css-1gtwvjp&quot;&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;Environment&lt;/p&gt;&lt;/blockquote&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;An &lt;code class=&quot;css-0&quot;&gt;environment&lt;/code&gt; is an object that holds all of the dependencies needed to produce side effects in our application. &lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;We will start with an empty environment for now, but we will eventually encapsulate the networking logic needed to talk to the iTunes API along with our main queue scheduler. The latter will ensure that we&amp;#x27;re receiving effect values on the main thread.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1592093219207/I4ko4tD8Q.png&quot; alt=&quot;Screen Shot 2020-06-13 at 5.05.46 PM.png&quot; class=&quot;css-0&quot;/&gt;&lt;/p&gt;&lt;blockquote class=&quot;css-1gtwvjp&quot;&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;Reducer&lt;/p&gt;&lt;/blockquote&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;A &lt;code class=&quot;css-0&quot;&gt;reducer&lt;/code&gt; is a pure function that takes in state, actions, and an environment, changes state, and returns any effects to be executed by the store at a later time.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;It contains the logic of how the current state should change to the next state and what effects should be executed by the store, if any. &lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;We&amp;#x27;ll start with a single reducer, but It&amp;#x27;s good practice to split out a large reducer into smaller, composable reducers that work on local state. We&amp;#x27;ll cover how to split up reducers as our application grows.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;Inside of our reducer, we&amp;#x27;ll be updating our state. Our reducer expects us to return an effect, but we can return &lt;code class=&quot;css-0&quot;&gt;.none&lt;/code&gt; for now to get our application compiling. We&amp;#x27;ll set up the effect to call the iTunes API later.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1592093903116/BhN1Oy0W1.png&quot; alt=&quot;Screen Shot 2020-06-13 at 5.18.09 PM.png&quot; class=&quot;css-0&quot;/&gt;&lt;/p&gt;&lt;h2 class=&quot;css-1bzbprl&quot;&gt;Initializing the Store&lt;/h2&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;The &lt;code class=&quot;css-0&quot;&gt;store&lt;/code&gt; contains the state, reducer, and environment for a SwiftUI view. It receives actions that are sent by the view store in order to run the reducers and any effects.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;It&amp;#x27;s good practice to initialize the entire global store at the root-level, but slice more local state into a child view using the &lt;code class=&quot;css-0&quot;&gt;scope&lt;/code&gt; method. We will cover this later, but essentially this helps us keep child views from knowing too much about what&amp;#x27;s happening outside of itself.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;Let&amp;#x27;s navigate to our root view (by default it&amp;#x27;s &lt;code class=&quot;css-0&quot;&gt;ContentView&lt;/code&gt;) and pull in the TCA library by typing &lt;code class=&quot;css-0&quot;&gt;import ComposableArchitecture&lt;/code&gt;. &lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;Above the view&amp;#x27;s body property, we&amp;#x27;ll add the store. It will be of type &lt;code class=&quot;css-0&quot;&gt;Store&lt;/code&gt; that is provided by TCA and be generic on our root level state and action. &lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1592094587459/0jp99CBCR.png&quot; alt=&quot;Screen Shot 2020-06-13 at 5.29.34 PM.png&quot; class=&quot;css-0&quot;/&gt;&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;Now, we need to initialize our store along in our preview struct. We&amp;#x27;ll start with an empty string as our &lt;code class=&quot;css-0&quot;&gt;searchTerm&lt;/code&gt;. &lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1592096603753/-Fm2jwCu2.png&quot; alt=&quot;Screen Shot 2020-06-13 at 6.02.59 PM.png&quot; class=&quot;css-0&quot;/&gt;&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;In the &lt;code class=&quot;css-0&quot;&gt;SceneDelegate&lt;/code&gt; file, add &lt;code class=&quot;css-0&quot;&gt;import ComposableArchitecture&lt;/code&gt; at the top. Then look for where the &lt;code class=&quot;css-0&quot;&gt;contentView&lt;/code&gt; gets assigned. This is where we will initialize our store. &lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1592094934704/4Ln8AI8Te.png&quot; alt=&quot;Screen Shot 2020-06-13 at 5.35.19 PM.png&quot; class=&quot;css-0&quot;/&gt;&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;Now, our application will build and the entry point to our application is the &lt;code class=&quot;css-0&quot;&gt;ContentView&lt;/code&gt;.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;All of the initial TCA boilerplate has been set up and we can start woking on our application logic. &lt;/p&gt;&lt;h2 class=&quot;css-1bzbprl&quot;&gt;Implementing the ViewStore&lt;/h2&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;If any SwiftUI view needs access to the store in TCA, it must go through the &lt;code class=&quot;css-0&quot;&gt;viewStore&lt;/code&gt; - an object that observes state and sends actions.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;It&amp;#x27;s used along with &lt;code class=&quot;css-0&quot;&gt;WithViewStore&lt;/code&gt; which is a custom SwiftUI view provided by TCA that takes in a store and returns a view. &lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;Going through another object to get access to state and actions instead of just referencing the store inside of a view may seem unusual, but this was done to maximize performance. &lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;When state changes inside of the store, the store will publish its changes to all views who are subscribed to it and SwiftUI will re-invoke the body inside of that view. &lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;Even if the parent is just passing a property down to a child view, the parent will re-render if it&amp;#x27;s subscribed to that change. Unnecessary re-renders are bad for performance, and the view store allows us to avoid that by focusing on only the state we need to.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;In the root view, let&amp;#x27;s wrap our Text view with &lt;code class=&quot;css-0&quot;&gt;WithViewStore&lt;/code&gt;. We can then replace the boilerplate content with the &lt;code class=&quot;css-0&quot;&gt;searchTerm&lt;/code&gt; we have in our &lt;code class=&quot;css-0&quot;&gt;AppState&lt;/code&gt;.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1592096336766/pDY-xdA9Q.png&quot; alt=&quot;Screen Shot 2020-06-13 at 5.58.47 PM.png&quot; class=&quot;css-0&quot;/&gt;&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;Now, if we change our &lt;code class=&quot;css-0&quot;&gt;searchTerm&lt;/code&gt; in the preview, we&amp;#x27;ll see our canvas update with the new state in real time.&lt;/p&gt;&lt;h2 class=&quot;css-1bzbprl&quot;&gt;Triggering State Changes with Actions&lt;/h2&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;As previously mentioned, state in TCA is read-only by design. This means that we can&amp;#x27;t write directly to state, but we can express our intent to change state by dispatching an action. The reducer that handles that action then responds by transforming state.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;We won&amp;#x27;t need the &lt;code class=&quot;css-0&quot;&gt;Text&lt;/code&gt; view for our search feature, but we can keep it here for some visual debugging so we can track the state of our current &lt;code class=&quot;css-0&quot;&gt;searchTerm&lt;/code&gt;. We can add prepend the state with a string so we can see it on screen even if the state property is empty.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1592097934785/1WG3vex0l.png&quot; alt=&quot;Screen Shot 2020-06-13 at 6.25.23 PM.png&quot; class=&quot;css-0&quot;/&gt;&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;In order to get the user&amp;#x27;s text input for our search, we&amp;#x27;ll add a &lt;code class=&quot;css-0&quot;&gt;TextField&lt;/code&gt; view inside of our &lt;code class=&quot;css-0&quot;&gt;WithViewStore&lt;/code&gt;. &lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;In a regular SwiftUI app, we&amp;#x27;d update the state of the query with a two-way binding via the &lt;code class=&quot;css-0&quot;&gt;@Binding&lt;/code&gt; property wrapper, but with TCA we want to prevent direct writes to state. For this scenario, TCA has a helper on the view store called a &lt;code class=&quot;css-0&quot;&gt;binding&lt;/code&gt;.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;Instead of a direct state write, we will only read state and declare an action to be sent through TCA when a state change should happen. &lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1592098197587/7GVvt5aZz.png&quot; alt=&quot;Screen Shot 2020-06-13 at 6.29.47 PM.png&quot; class=&quot;css-0&quot;/&gt;&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;Run the app and we should see state updating in the Text and TextField views in real time.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1592171005819/Tp794jF_E.gif&quot; alt=&quot;itunes_kstate.gif&quot; class=&quot;css-0&quot;/&gt;&lt;/p&gt;&lt;h2 class=&quot;css-1bzbprl&quot;&gt;Debugging the Reducer&lt;/h2&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;We covered a way to use the &lt;code class=&quot;css-0&quot;&gt;Text&lt;/code&gt; view to visually debug our state changes, but this is not a scalable solution for tracking state changes in our application. There&amp;#x27;s a better way to track them in TCA without print-bombing and interrupting our application with breakpoints.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;TCA ships with a &lt;code class=&quot;css-0&quot;&gt;debug&lt;/code&gt; method we can chain to our reducer. We just simply have to add &lt;code class=&quot;css-0&quot;&gt;.debug()&lt;/code&gt; to our reducer.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1592166930849/88vou7_pL.png&quot; alt=&quot;Screen Shot 2020-06-14 at 1.35.16 PM.png&quot; class=&quot;css-0&quot;/&gt;&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;Now, when any state changes happen, we can look at our console and TCA will tell us when it&amp;#x27;s received an action and give us a diff of what state property has changed.&lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1592166999326/EEpoRl-_3.png&quot; alt=&quot;Screen Shot 2020-06-14 at 1.31.24 PM.png&quot; class=&quot;css-0&quot;/&gt;&lt;/p&gt;&lt;h2 class=&quot;css-1bzbprl&quot;&gt;Up Next&lt;/h2&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;We covered &lt;em class=&quot;css-0&quot;&gt;a lot&lt;/em&gt; of concepts in this post, but they&amp;#x27;re all essential to understanding the benefits of how well this architecture does its job. &lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;One of the pain points I had when first learning Redux in the React.js ecosystem was how much boilerplate code I had to write before writing business logic for my application. I think that&amp;#x27;s a valid concern here for TCA, but, in my opinion, it&amp;#x27;s a small tradeoff for a huge benefit. &lt;/p&gt;&lt;p class=&quot;css-1bkk5q4&quot;&gt;In the next post, we will set up the environment and API client so we can call the iTunes API with our search query. Then, we will set up a SwiftUI &lt;code class=&quot;css-0&quot;&gt;NavigationView&lt;/code&gt; and parse the response so we can render the list of artist results.&lt;/p&gt;</content:encoded></item></channel></rss>