<?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: Chris Belsole</title>
    <description>The latest articles on Forem by Chris Belsole (@cbelsole).</description>
    <link>https://forem.com/cbelsole</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%2F243385%2Fb66cbf70-6e29-4885-86d8-799d4f0beb5f.jpeg</url>
      <title>Forem: Chris Belsole</title>
      <link>https://forem.com/cbelsole</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/cbelsole"/>
    <language>en</language>
    <item>
      <title>Convert to React Hooks in 6 easy steps</title>
      <dc:creator>Chris Belsole</dc:creator>
      <pubDate>Sat, 21 Mar 2020 20:25:47 +0000</pubDate>
      <link>https://forem.com/cbelsole/convert-to-react-hooks-in-6-easy-steps-1ggo</link>
      <guid>https://forem.com/cbelsole/convert-to-react-hooks-in-6-easy-steps-1ggo</guid>
      <description>&lt;p&gt;&lt;a href="https://reactjs.org/docs/hooks-intro.html"&gt;React hooks&lt;/a&gt; were released in version &lt;a href="https://github.com/facebook/react/blob/master/CHANGELOG.md#1680-february-6-2019"&gt;16.8.0&lt;/a&gt;, and since then &lt;a href="https://dev.to/search?q=react%20hooks"&gt;we’ve all&lt;/a&gt; been trying to figure out how to use them effectively and convert our components so that using newer versions of React is not an upgrade nightmare. In this article we are going to discuss the 6 steps for moving your React components to hooks using an &lt;a href="https://github.com/cbelsole/controller_hooks_example"&gt;example to-do application&lt;/a&gt; written in Typescript that starts with the controller pattern and &lt;a href="https://github.com/cbelsole/controller_hooks_example/commits/master"&gt;commit by commit&lt;/a&gt; lays out my methodology for moving components. There are more complex examples, but this article should give you a good grounding in how to think about migrating your components.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Protip:&lt;/strong&gt; Using React hooks can be a replacement for Redux bringing down the number of dependencies in your application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Step 1: Select the component to convert
&lt;/h1&gt;

&lt;p&gt;Let’s chat for a second about what our example to-do app looks like.&lt;/p&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TsLwGEgy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://raw.githubusercontent.com/cbelsole/controller_hooks_example/master/todo_app_demo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TsLwGEgy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://raw.githubusercontent.com/cbelsole/controller_hooks_example/master/todo_app_demo.gif" alt="to-do app demo" title="to-do app demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see we have a list of to-do’s that can be completed with a button underneath that checks if all to-do’s are complete. For this example we are going to convert the &lt;a href="https://github.com/cbelsole/controller_hooks_example/blob/cb885358b697ff1096c7de6685d0a7e8ace9da53/src/components/controller.tsx"&gt;&lt;code&gt;Controller.tsx&lt;/code&gt;&lt;/a&gt; component which declares an empty list of to-do’s and renders a loading state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;State&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;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;todos&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="err"&gt;…&lt;/span&gt;
  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;todos&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="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;loading...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Grabs data from the API via &lt;code&gt;componentDidMount()&lt;/code&gt; and populates the list of to-do’s:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight tsx"&gt;&lt;code&gt;  &lt;span class="nx"&gt;componentDidMount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;getTodos&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;todos&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;And renders the &lt;a href="https://github.com/cbelsole/controller_hooks_example/blob/cb885358b697ff1096c7de6685d0a7e8ace9da53/src/components/todoList.tsx"&gt;&lt;code&gt;&amp;lt;TodoList /&amp;gt;&lt;/code&gt;&lt;/a&gt; along with the &lt;a href="https://github.com/cbelsole/controller_hooks_example/blob/cb885358b697ff1096c7de6685d0a7e8ace9da53/src/components/controller.tsx#L47"&gt;&lt;code&gt;All complete?&lt;/code&gt;&lt;/a&gt; button while passing down the complete callback:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TodoList&lt;/span&gt; &lt;span class="na"&gt;completeTodo&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completeTodo&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;todos&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="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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAllComplete&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;All complete?&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here’s the full code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&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;getTodos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;completeTodo&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;completeTodoAPI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;iTodo&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="s2"&gt;../api/todos&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;TodoList&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./todoList&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;iTodo&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="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;State&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;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;todos&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="nx"&gt;componentDidMount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;getTodos&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;completeTodo&lt;/span&gt; &lt;span class="o"&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;completeTodoAPI&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="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;isAllComplete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&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="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;todos&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;todos&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="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Todos are not complete.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Todos are complete.&lt;/span&gt;&lt;span class="dl"&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;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;todos&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="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;loading...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TodoList&lt;/span&gt; &lt;span class="na"&gt;completeTodo&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completeTodo&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;todos&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="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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAllComplete&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;All complete?&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&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;h1&gt;
  
  
  Step 2: Convert your class to a function
&lt;/h1&gt;

&lt;p&gt;Here we are changing our class to a function and returning the JSX elements from that function. So we move all of our returns statements outside of the &lt;code&gt;render()&lt;/code&gt; method. In Typescript &lt;code&gt;React.FunctionalComponent&lt;/code&gt; (&lt;code&gt;React.FC&lt;/code&gt;) is the interface for a function component. For Javascript you would just declare a function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/src/components/controller.tsx b/src/components/controller.tsx
index 7184893..e310613 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/src/components/controller.tsx
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/src/components/controller.tsx
&lt;/span&gt;&lt;span class="p"&gt;@@ -7,7 +7,7 @@&lt;/span&gt; interface State {
   todos: iTodo[];
 }

-export default class Controller extends React.Component&amp;lt;Props, State&amp;gt; {
&lt;span class="gi"&gt;+const Controller: React.FunctionComponent = () =&amp;gt;  {
&lt;/span&gt;   constructor(props: Props) {
     super(props);
     this.state = { todos: [] };
&lt;span class="p"&gt;@@ -34,7 +34,6 @@&lt;/span&gt; export default class Controller extends React.Component&amp;lt;Props, State&amp;gt; {
     alert('Todos are complete.');
   };

-  render() {
   const { todos } = this.state;

   if (!todos.length) {
&lt;span class="p"&gt;@@ -47,5 +46,7 @@&lt;/span&gt; export default class Controller extends React.Component&amp;lt;Props, State&amp;gt; {
       &amp;lt;button onClick={this.isAllComplete}&amp;gt;All complete?&amp;lt;/button&amp;gt;
     &amp;lt;/div&amp;gt;
   );
&lt;span class="gi"&gt;+
&lt;/span&gt; }
&lt;span class="gd"&gt;-}
&lt;/span&gt;&lt;span class="gi"&gt;+
+export default Controller;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 3: Extract class methods to consts
&lt;/h1&gt;

&lt;p&gt;Extracting &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes"&gt;static and class methods&lt;/a&gt; to consts is the simplest analogue I've found for the structure of a functional component. Class methods rely on state. So they are inlined with the function. Static methods don't rely on state. So they go outside of the function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/src/components/controller.tsx b/src/components/controller.tsx
index e310613..4322bf2 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/src/components/controller.tsx
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/src/components/controller.tsx
&lt;/span&gt;&lt;span class="p"&gt;@@ -17,11 +17,11 @@&lt;/span&gt; const Controller: React.FunctionComponent = () =&amp;gt;  {
     getTodos().then(todos =&amp;gt; this.setState({ todos }));
   }

-  completeTodo = (item: string) =&amp;gt; {
&lt;span class="gi"&gt;+  const completeTodo = (item: string) =&amp;gt; {
&lt;/span&gt;     completeTodoAPI(item).then(todos =&amp;gt; this.setState({ todos }));
   };

-  isAllComplete = () =&amp;gt; {
&lt;span class="gi"&gt;+  const isAllComplete = () =&amp;gt; {
&lt;/span&gt;     const { todos } = this.state;

     for (let i = 0; i &amp;lt; todos.length; i++) {
&lt;span class="p"&gt;@@ -42,8 +42,8 @@&lt;/span&gt; const Controller: React.FunctionComponent = () =&amp;gt;  {

   return (
     &amp;lt;div&amp;gt;
&lt;span class="gd"&gt;-      &amp;lt;TodoList completeTodo={this.completeTodo} todos={todos} /&amp;gt;
-      &amp;lt;button onClick={this.isAllComplete}&amp;gt;All complete?&amp;lt;/button&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+      &amp;lt;TodoList completeTodo={completeTodo} todos={todos} /&amp;gt;
+      &amp;lt;button onClick={isAllComplete}&amp;gt;All complete?&amp;lt;/button&amp;gt;
&lt;/span&gt;     &amp;lt;/div&amp;gt;
   );
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 4: Extract state via useState()
&lt;/h1&gt;

&lt;p&gt;Ahhh, we finally get to use hooks. &lt;a href="https://reactjs.org/docs/hooks-state.html"&gt;&lt;code&gt;useState()&lt;/code&gt;&lt;/a&gt; is our first hook we are going to use to extract the state of our component. This hook works by declaring the default state and returning the first parameter as the state and the second as a function to update the state. Since we inlined all the class methods the new state should be accessible in the functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/src/components/controller.tsx b/src/components/controller.tsx
index 4322bf2..000b077 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/src/components/controller.tsx
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/src/components/controller.tsx
&lt;/span&gt;&lt;span class="p"&gt;@@ -1,29 +1,21 @@&lt;/span&gt;
&lt;span class="gd"&gt;-import * as React from 'react';
&lt;/span&gt;&lt;span class="gi"&gt;+import React, { useState } from 'react';
&lt;/span&gt; import { getTodos, completeTodo as completeTodoAPI, iTodo } from '../api/todos';
 import TodoList from './todoList';

 interface Props {}
&lt;span class="gd"&gt;-interface State {
-  todos: iTodo[];
-}
&lt;/span&gt;
 const Controller: React.FunctionComponent = () =&amp;gt;  {
&lt;span class="gd"&gt;-  constructor(props: Props) {
-    super(props);
-    this.state = { todos: [] };
-  }
&lt;/span&gt;&lt;span class="gi"&gt;+  const [todos, setTodos] = useState&amp;lt;iTodo[]&amp;gt;([])
&lt;/span&gt;
   componentDidMount() {
&lt;span class="gd"&gt;-    getTodos().then(todos =&amp;gt; this.setState({ todos }));
&lt;/span&gt;&lt;span class="gi"&gt;+    getTodos().then(todos =&amp;gt; setTodos(todos));
&lt;/span&gt;   }

   const completeTodo = (item: string) =&amp;gt; {
&lt;span class="gd"&gt;-    completeTodoAPI(item).then(todos =&amp;gt; this.setState({ todos }));
&lt;/span&gt;&lt;span class="gi"&gt;+    completeTodoAPI(item).then(todos =&amp;gt; setTodos(todos));
&lt;/span&gt;   };

   const isAllComplete = () =&amp;gt; {
&lt;span class="gd"&gt;-    const { todos } = this.state;
-
&lt;/span&gt;     for (let i = 0; i &amp;lt; todos.length; i++) {
       if (!todos[i].done) {
         alert('Todos are not complete.');
&lt;span class="p"&gt;@@ -34,8 +26,6 @@&lt;/span&gt; const Controller: React.FunctionComponent = () =&amp;gt;  {
     alert('Todos are complete.');
   };

-  const { todos } = this.state;
&lt;span class="gd"&gt;-
&lt;/span&gt;   if (!todos.length) {
     return &amp;lt;div&amp;gt;loading...&amp;lt;/div&amp;gt;;
   }
&lt;span class="err"&gt;(END)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 5: Convert lifecycle methods
&lt;/h1&gt;

&lt;p&gt;Here we have some interesting options depending on what hooks we are converting. Check out &lt;a href="https://dev.to/trentyang/replace-lifecycle-with-hooks-in-react-3d4n"&gt;this article&lt;/a&gt; for some common conversions. We only want our &lt;a href="https://reactjs.org/docs/hooks-effect.html"&gt;&lt;code&gt;useEffect()&lt;/code&gt;&lt;/a&gt; function to run when the component mounts. So we'll pass it an empty array (&lt;code&gt;[]&lt;/code&gt;) in the second argument signifying it should run once and not again since there are no parameters in the array to cause it to refresh.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/src/components/controller.tsx b/src/components/controller.tsx
index 000b077..0f85564 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/src/components/controller.tsx
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/src/components/controller.tsx
&lt;/span&gt;&lt;span class="p"&gt;@@ -1,15 +1,11 @@&lt;/span&gt;
&lt;span class="gd"&gt;-import React, { useState } from 'react';
&lt;/span&gt;&lt;span class="gi"&gt;+import React, { useState, useEffect } from 'react';
&lt;/span&gt; import { getTodos, completeTodo as completeTodoAPI, iTodo } from '../api/todos';
 import TodoList from './todoList';

 interface Props {}

 const Controller: React.FunctionComponent = () =&amp;gt; {
&lt;span class="gd"&gt;-  const [todos, setTodos] = useState&amp;lt;iTodo[]&amp;gt;([])
-
-  componentDidMount() {
-    getTodos().then(todos =&amp;gt; setTodos(todos));
-  }
&lt;/span&gt;&lt;span class="gi"&gt;+  const [todos, setTodos] = useState&amp;lt;iTodo[]&amp;gt;([]);
&lt;/span&gt;
   const completeTodo = (item: string) =&amp;gt; {
     completeTodoAPI(item).then(todos =&amp;gt; setTodos(todos));
&lt;span class="p"&gt;@@ -26,6 +22,10 @@&lt;/span&gt; const Controller: React.FunctionComponent = () =&amp;gt;  {
     alert('Todos are complete.');
   };

+  useEffect(() =&amp;gt; {
&lt;span class="gi"&gt;+    getTodos().then(todos =&amp;gt; setTodos(todos));
+  }, []);
+
&lt;/span&gt;   if (!todos.length) {
     return &amp;lt;div&amp;gt;loading...&amp;lt;/div&amp;gt;;
   }
&lt;span class="p"&gt;@@ -36,7 +36,6 @@&lt;/span&gt; const Controller: React.FunctionComponent = () =&amp;gt;  {
       &amp;lt;button onClick={isAllComplete}&amp;gt;All complete?&amp;lt;/button&amp;gt;
     &amp;lt;/div&amp;gt;
   );
&lt;span class="gd"&gt;-
-}
&lt;/span&gt;&lt;span class="gi"&gt;+};
&lt;/span&gt;
 export default Controller;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 6: Cleanup unused components
&lt;/h1&gt;

&lt;p&gt;A simple but important step, clean up your code if you have anything left over. Future you will be happy you took the time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/src/components/controller.tsx b/src/components/controller.tsx
index 0f85564..a4eaac9 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/src/components/controller.tsx
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/src/components/controller.tsx
&lt;/span&gt;&lt;span class="p"&gt;@@ -2,8 +2,6 @@&lt;/span&gt; import React, { useState, useEffect } from 'react';
 import { getTodos, completeTodo as completeTodoAPI, iTodo } from '../api/todos';
 import TodoList from './todoList';

-interface Props {}
&lt;span class="gd"&gt;-
&lt;/span&gt; const Controller: React.FunctionComponent = () =&amp;gt; {
   const [todos, setTodos] = useState&amp;lt;iTodo[]&amp;gt;([]);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  (Bonus) Step 7: Move state management to context/provider
&lt;/h1&gt;

&lt;p&gt;At this point you have a working functional component. So why not just stop here and move on to your next task? The answer is a bit complex and touches on architectural principals so first, let's talk a little about &lt;a href="https://en.wikipedia.org/wiki/SOLID"&gt;SOLID&lt;/a&gt; principals, state management, and &lt;a href="https://en.wikipedia.org/wiki/Coupling_(computer_programming)"&gt;component coupling&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;SOLID principals are a set of ideas for building maintainable software acting as guides for making decisions about architecting complex systems. The S in SOLID stands for the &lt;a href="https://en.wikipedia.org/wiki/Single-responsibility_principle"&gt;Single Responsibility Principal&lt;/a&gt; which states that "A class should only have one reason to change." In short, things do one thing. Since React is a frontend library it is easy and often required to break this principal since components are often rendering HTML and managing state. This works well enough but it often becomes unmaintainable when you have to rewrite your code for another use case since the state that drives your components is kept at the highest level.&lt;/p&gt;

&lt;p&gt;This is where we start talking about local state vs global state. Local state is state local to your component. Think filling out an HTML form or keeping track of button clicks. That info needs to live somewhere, and often that's in the state of the component rendering the HTML. Global state on the other hand is shared across components. Imagine grabbing a user session form your API and storing that somewhere so that you can use the user's name and email to display across your application. If we used a pure component architecture to store global state we have to fetch data in the top level component and then pass it down through all other components to the one that needs it much like the the &lt;a href="https://github.com/cbelsole/controller_hooks_example/blob/controller_component_pattern/src/components/controller.tsx"&gt;&lt;code&gt;&amp;lt;Controller /&amp;gt;&lt;/code&gt;&lt;/a&gt; passing the &lt;a href="https://github.com/cbelsole/controller_hooks_example/blob/controller_component_pattern/src/components/controller.tsx#L20"&gt;&lt;code&gt;completeTodo()&lt;/code&gt;&lt;/a&gt; function through the &lt;a href="https://github.com/cbelsole/controller_hooks_example/blob/controller_component_pattern/src/components/todoList.tsx"&gt;&lt;code&gt;&amp;lt;TodoList /&amp;gt;&lt;/code&gt;&lt;/a&gt; to the &lt;a href="https://github.com/cbelsole/controller_hooks_example/blob/controller_component_pattern/src/components/todo.tsx"&gt;&lt;code&gt;&amp;lt;Todo /&amp;gt;&lt;/code&gt;&lt;/a&gt; component so that the button on the &lt;a href="https://github.com/cbelsole/controller_hooks_example/blob/controller_component_pattern/src/components/todo.tsx"&gt;&lt;code&gt;&amp;lt;Todo /&amp;gt;&lt;/code&gt;&lt;/a&gt; component can modify the state of a to-do. We can see in this example that this leads to tight coupling of components.&lt;/p&gt;

&lt;p&gt;Why do we want to avoid tight coupling? Imagine writing a complex grocery store application where everything is tied to a single payments processing system. Something happens to them internally and now your payments processing system is shutting down. How are you going to integrate a new payments processing system into your application? You have to rewrite your ordering, refunding, and revenue systems which incurs a lot of risk when these things are so critical to your business. Alternatively, let's think of a scenario where your payments processing system is behind an abstraction. The abstraction is aware of orders and knows how to refund and calculate revenue. Now when you need to rewrite your system to deal with all the new code you only have to rewrite the logic underneath that abstraction. This is also the &lt;a href="https://en.wikipedia.org/wiki/Dependency_inversion_principle"&gt;D in SOLID&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Following &lt;a href="https://en.wikipedia.org/wiki/SOLID"&gt;SOLID&lt;/a&gt; principals and thinking ahead about how your components are tied together are ideas that make a long lasting application maintainable. It is often faster to write code that works in the now, but if you engrain these concepts into your fingers future you will have a much easier time dealing with bugs and changing your software.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's put the background into pratice
&lt;/h2&gt;

&lt;p&gt;With all that in mind let's dive into the code. First we'll write our &lt;a href="https://github.com/cbelsole/controller_hooks_example/blob/master/src/components/todoProvider.tsx"&gt;&lt;code&gt;&amp;lt;TodoProvider /&amp;gt;&lt;/code&gt;&lt;/a&gt; that holds our global state with the capability to get and complete to-do's from the API. Notice that it returns its children wrapped in the provider. This is what allows us to use the context in the component chain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&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="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&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;getTodos&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;getTodosAPI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;completeTodo&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;completeTodoAPI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;iTodo&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="s2"&gt;../api/todos&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;iTodoContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;iTodo&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;completeTodo&lt;/span&gt;&lt;span class="p"&gt;:&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;getTodos&lt;/span&gt;&lt;span class="p"&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="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;TodoProviderProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&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;todoContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;iTodoContext&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;todos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;completeTodo&lt;/span&gt;&lt;span class="p"&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="na"&gt;getTodos&lt;/span&gt;&lt;span class="p"&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="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TodoProvider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FunctionComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;children&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;TodoProviderProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;iTodo&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;getTodos&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="nx"&gt;getTodosAPI&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&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;completeTodo&lt;/span&gt; &lt;span class="o"&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;completeTodoAPI&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="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;todoContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;completeTodo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getTodos&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;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/todoContext.Provider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;TodoProvider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, we'll wrap our &lt;a href="https://github.com/cbelsole/controller_hooks_example/blob/master/src/components/controller.tsx"&gt;&lt;code&gt;&amp;lt;Controller /&amp;gt;&lt;/code&gt;&lt;/a&gt; in the provider so that we can call &lt;a href="https://reactjs.org/docs/hooks-reference.html#usecontext"&gt;&lt;code&gt;useContext()&lt;/code&gt;&lt;/a&gt; within the component chain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/src/App.tsx b/src/App.tsx
index f7b1217..83ce739 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/src/App.tsx
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/src/App.tsx
&lt;/span&gt;&lt;span class="p"&gt;@@ -1,10 +1,13 @@&lt;/span&gt;
 import React from 'react';
 import Controller from './components/controller';
&lt;span class="gi"&gt;+import TodoProvider from './components/todoProvider';
&lt;/span&gt;
 function App() {
   return (
     &amp;lt;div&amp;gt;
&lt;span class="gi"&gt;+      &amp;lt;TodoProvider&amp;gt;
&lt;/span&gt;         &amp;lt;Controller /&amp;gt;
&lt;span class="gi"&gt;+      &amp;lt;/TodoProvider&amp;gt;
&lt;/span&gt;     &amp;lt;/div&amp;gt;
   );
 }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We'll then rewrite our &lt;a href="https://github.com/cbelsole/controller_hooks_example/blob/master/src/components/controller.tsx"&gt;&lt;code&gt;&amp;lt;Controller /&amp;gt;&lt;/code&gt;&lt;/a&gt; to call &lt;a href="https://reactjs.org/docs/hooks-reference.html#usecontext"&gt;&lt;code&gt;useContext()&lt;/code&gt;&lt;/a&gt; to get to-do's and pass them down to it's children while breaking the dependency of passing down the &lt;a href="https://github.com/cbelsole/controller_hooks_example/blob/master/src/components/todoProvider.tsx#L31"&gt;&lt;code&gt;completeTodo()&lt;/code&gt;&lt;/a&gt; function making the component chain loosely coupled since it still relies on the data but not the interactions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/src/components/controller.tsx b/src/components/controller.tsx
index a4eaac9..1159fc7 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/src/components/controller.tsx
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/src/components/controller.tsx
&lt;/span&gt;&lt;span class="p"&gt;@@ -1,13 +1,9 @@&lt;/span&gt;
&lt;span class="gd"&gt;-import React, { useState, useEffect } from 'react';
-import { getTodos, completeTodo as completeTodoAPI, iTodo } from '../api/todos';
&lt;/span&gt;&lt;span class="gi"&gt;+import React, { useEffect, useContext } from 'react';
&lt;/span&gt; import TodoList from './todoList';
&lt;span class="gi"&gt;+import { todoContext } from './todoProvider';
&lt;/span&gt;
 const Controller: React.FunctionComponent = () =&amp;gt; {
&lt;span class="gd"&gt;-  const [todos, setTodos] = useState&amp;lt;iTodo[]&amp;gt;([]);
-
-  const completeTodo = (item: string) =&amp;gt; {
-    completeTodoAPI(item).then(todos =&amp;gt; setTodos(todos));
-  };
&lt;/span&gt;&lt;span class="gi"&gt;+  const { todos, getTodos } = useContext(todoContext);
&lt;/span&gt;
   const isAllComplete = () =&amp;gt; {
     for (let i = 0; i &amp;lt; todos.length; i++) {
&lt;span class="p"&gt;@@ -21,8 +17,8 @@&lt;/span&gt; const Controller: React.FunctionComponent = () =&amp;gt; {
   };

   useEffect(() =&amp;gt; {
&lt;span class="gd"&gt;-    getTodos().then(todos =&amp;gt; setTodos(todos));
-  }, []);
&lt;/span&gt;&lt;span class="gi"&gt;+    getTodos();
+  }, [getTodos]);
&lt;/span&gt;
   if (!todos.length) {
     return &amp;lt;div&amp;gt;loading...&amp;lt;/div&amp;gt;;
&lt;span class="p"&gt;@@ -30,7 +26,7 @@&lt;/span&gt; const Controller: React.FunctionComponent = () =&amp;gt; {

   return (
     &amp;lt;div&amp;gt;
&lt;span class="gd"&gt;-      &amp;lt;TodoList completeTodo={completeTodo} todos={todos} /&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+      &amp;lt;TodoList todos={todos} /&amp;gt;
&lt;/span&gt;       &amp;lt;button onClick={isAllComplete}&amp;gt;All complete?&amp;lt;/button&amp;gt;
     &amp;lt;/div&amp;gt;
   );
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/cbelsole/controller_hooks_example/blob/master/src/components/todoList.tsx"&gt;&lt;code&gt;&amp;lt;TodoList /&amp;gt;&lt;/code&gt;&lt;/a&gt; also gets edited to no longer pass down the &lt;a href="https://github.com/cbelsole/controller_hooks_example/blob/master/src/components/todoProvider.tsx#L31"&gt;&lt;code&gt;completeTodo()&lt;/code&gt;&lt;/a&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/src/components/todoList.tsx b/src/components/todoList.tsx
index e69edba..4f664b8 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/src/components/todoList.tsx
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/src/components/todoList.tsx
&lt;/span&gt;&lt;span class="p"&gt;@@ -4,15 +4,14 @@&lt;/span&gt; import Todo from './todo';

 interface Props {
   todos: Array&amp;lt;iTodo&amp;gt;;
&lt;span class="gd"&gt;-  completeTodo: (item: string) =&amp;gt; void;
&lt;/span&gt; }

-const TodoList: React.FC&amp;lt;Props&amp;gt; = ({ todos, completeTodo }) =&amp;gt; {
&lt;span class="gi"&gt;+const TodoList: React.FC&amp;lt;Props&amp;gt; = ({ todos }) =&amp;gt; {
&lt;/span&gt;   return (
     &amp;lt;ul&amp;gt;
       {todos.map(todo =&amp;gt; (
         &amp;lt;li&amp;gt;
&lt;span class="gd"&gt;-          &amp;lt;Todo completeTodo={completeTodo} {...todo} /&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+          &amp;lt;Todo {...todo} /&amp;gt;
&lt;/span&gt;         &amp;lt;/li&amp;gt;
       ))}
     &amp;lt;/ul&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Finally &lt;a href="https://github.com/cbelsole/controller_hooks_example/blob/master/src/components/todo.tsx"&gt;&lt;code&gt;&amp;lt;Todo&amp;gt;&lt;/code&gt;&lt;/a&gt; calls &lt;a href="https://reactjs.org/docs/hooks-reference.html#usecontext"&gt;&lt;code&gt;useContext()&lt;/code&gt;&lt;/a&gt; to get the &lt;a href="https://github.com/cbelsole/controller_hooks_example/blob/master/src/components/todoProvider.tsx#L31"&gt;&lt;code&gt;completeTodo()&lt;/code&gt;&lt;/a&gt; function and update itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/src/components/todo.tsx b/src/components/todo.tsx
index 47b0e44..75de4ff 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/src/components/todo.tsx
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/src/components/todo.tsx
&lt;/span&gt;&lt;span class="p"&gt;@@ -1,11 +1,12 @@&lt;/span&gt;
&lt;span class="gd"&gt;-import * as React from 'react';
&lt;/span&gt;&lt;span class="gi"&gt;+import React, { useContext } from 'react';
&lt;/span&gt; import { iTodo } from '../api/todos';
&lt;span class="gi"&gt;+import { todoContext } from './todoProvider';
&lt;/span&gt;
-interface Props extends iTodo {
&lt;span class="gd"&gt;-  completeTodo: (item: string) =&amp;gt; void;
-}
&lt;/span&gt;&lt;span class="gi"&gt;+interface Props extends iTodo {}
+
+const Todo: React.FC&amp;lt;Props&amp;gt; = ({ item, done }) =&amp;gt; {
+  const { completeTodo } = useContext(todoContext);
&lt;/span&gt;
-const Todo: React.FC&amp;lt;Props&amp;gt; = ({ item, done, completeTodo }) =&amp;gt; {
   return (
     &amp;lt;div&amp;gt;
       task: {item} is {done ? 'done' : 'not done'}{' '}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After all that we have an abstracted functional app working off of global and local state where appropriate. I hope you found this guide useful. Please get in contact with me if you have any feedback.&lt;/p&gt;

</description>
      <category>react</category>
      <category>hooks</category>
    </item>
    <item>
      <title>My personal journey setting up a blog</title>
      <dc:creator>Chris Belsole</dc:creator>
      <pubDate>Tue, 10 Mar 2020 12:17:04 +0000</pubDate>
      <link>https://forem.com/cbelsole/my-personal-journey-setting-up-a-blog-1gd5</link>
      <guid>https://forem.com/cbelsole/my-personal-journey-setting-up-a-blog-1gd5</guid>
      <description>&lt;p&gt;Like a moth to the flame I keep coming back to the idea of maintaining a personal blog. I’ve spun up a &lt;a href="https://jekyllrb.com/"&gt;Jekyll&lt;/a&gt; blog more than once and wrote some content only to abandon it days later. Until a bit ago cbelsole.github.com was still up and running. Since I haven’t touched it for 4 years it stood as a testament to set it and forget it infrastructure.&lt;/p&gt;

&lt;p&gt;So like, why do this again? Since my Jekyll days static site generators have gotten a lot more interesting. I use Gatsby (JS) professionally which has the ability to do plug-and-play server-side rendering. This is a huge advantage since you can cut perceived load time to a minimum by pre-rendering all of your react pages and ship the static site async after the page loads. Hugo (Go) promises to render pages in 1ms making generating thousands of pages fast. Being web developers, we owe it to ourselves to explore the tools of our field so that we can craft nuanced solutions for professional and personal projects.&lt;/p&gt;

&lt;h1&gt;
  
  
  Goals
&lt;/h1&gt;

&lt;p&gt;For my static site experiment I wanted to set a few goals with a focus on creating content and not configuration:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;I want a static site generator that works out of the box without a lot of configuration&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;My strengths don't lie in frontend development. So I need a template to work off of.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Blog posts should be easy to create. Experiment with a CRM for creating posts and managing content.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I want the hosting platform to be bulletproof so that I can leave the blog up for years without worrying about it being down.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I want to accomplish these goals on the cheap.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Picking a framework
&lt;/h1&gt;

&lt;p&gt;If we check &lt;a href="https://www.staticgen.com/"&gt;staticgen.com&lt;/a&gt; there are currently 281 options for creating a static site. That’s too many. So I shortened the list to &lt;a href="https://www.gatsbyjs.org/"&gt;Gatsby&lt;/a&gt; (JS) which I have production experience with and &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt; (Go) because I mainly work in Go these days and you get a lot of tooling for free.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gatsby
&lt;/h2&gt;

&lt;p&gt;Gatsby's ability for server-side rendering is appealing especially if you have a few pages that are going to be visited frequently. For this project though I want something that works out of the box and requires very little upkeep. If you’ve ever worked with JS in production you know that dependencies can cause a maintenance nightmare if you 1. Don’t lock them down and 2. Don’t keep them up to date. For example, try upgrading your version of React after being 2 major versions behind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hugo
&lt;/h2&gt;

&lt;p&gt;I have been following Hugo for a long time. I experimented with it once when it was first released and it lived up to its promise of rendering pages quickly. At the time the themes available were sparse and my strengths don’t lie in front end development. Since then their themes folder has grown to 299 themes as of the writing of this post. They all range in their capabilities like social integration and Google Analytics, but some of them look straight up professional. I’m looking at you &lt;a href="https://github.com/gcushen/hugo-academic"&gt;hugo-academic&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Protip:&lt;/strong&gt; Github user TrentSPalmer created a script to rank Hugo themes by stars &lt;a href="https://github.com/TrentSPalmer/hugo_themes_report"&gt;hugo_themes_report&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What about dependencies? Installing Hugo comes with a long list of dependencies, but since the only thing I installed is Hugo I can assume that they will manage that list for me. So upgrading Hugo should be fairly straightforward. That coupled with Go's promise to maintain backward compatibility lowers the tooling and maintenance costs. I did read a few cases where Hugo did not perform the same version over version, but I’ve lived a lifetime maintaining JS applications. So if I have to deal with the occasional upgrade bug from one dependency rather myriads I am fine with it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setup
&lt;/h1&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# create and enter directory&lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;cbelsole.com &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;cbelsole.com

&lt;span class="c"&gt;# create a new go module&lt;/span&gt;
go mod init github.com/cbelsole/cbelsole.com

&lt;span class="c"&gt;# install hugo and lock version&lt;/span&gt;
go get github.com/gohugoio/hugo

&lt;span class="c"&gt;# create new hugo site&lt;/span&gt;
hugo new site cbelsole.com &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;mv &lt;/span&gt;cbelsole.com/&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; cbelsole.com

&lt;span class="c"&gt;# add the mainroad theme&lt;/span&gt;
git submodule add https://github.com/vimux/mainroad themes/mainroad
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Content Management System Rabbithole
&lt;/h1&gt;

&lt;p&gt;To manage my blog tags and content I looked into &lt;a href="https://forestry.io"&gt;Forestry.io&lt;/a&gt; and &lt;a href="https://www.netlifycms.org"&gt;Netlify CMS&lt;/a&gt; since both of these had plug-and-play content tools that integrated with Github. The idea here is to make managing content easier by using a UI rather than editing post metadata manually.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; it did not work out. The need to integrate with their specific sites outweighed the benefits of a CMS, especially with so little content.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Netlify CMS
&lt;/h2&gt;

&lt;p&gt;The experiment started out with a lot of promise since in their words:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The folks at Netlify created Netlify CMS to fill a gap in the static site generation pipeline. There were some great proprietary headless CMS options, but no real contenders that were open source and extensible—that could turn into a community-built ecosystem like WordPress or Drupal. For that reason, Netlify CMS is made to be community-driven, and has never been locked to the Netlify platform (despite the name).&lt;/p&gt;

&lt;p&gt;If you hook up Netlify CMS to your website, you're basically adding a tool for content editors to make commits to your site repository without touching code or learning Git.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The downside here is that plugging in the CMS requires you to use their identity service for OAuth and that means you have to deploy via Netlify. This is not something I wanted to do since the price per usage is good compared to Zeit but not as good as AWS. You can host your own identity server, but that would necessitate standing up a server which would also increase costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Forestry.io
&lt;/h2&gt;

&lt;p&gt;Forestry.io is another Github based CMS provider that allows you to plug it into your website pretty seamlessly. When I got it setup I took a look at what was in front of me. I have a tag manager and a markdown editor. As the sole writer with only a single post this seemed like a premature optimization. Maybe when I am writing with multiple people with a more complex use case adding a CMS will be more of a need than a nice to have. For now, with &lt;a href="https://stackedit.io/"&gt;stackedit.io&lt;/a&gt; I have a good markdown editor and eventually I'll come up with a set of tags.&lt;/p&gt;

&lt;h1&gt;
  
  
  AWS Time
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/premiumsupport/knowledge-center/cloudfront-serve-static-website/"&gt;This guide&lt;/a&gt; describes how to create a static s3 site with HTTPS via CloudFront. After the $12 of registering the domain name with my current usage AWS costs me around $1.03 a month. That's well within what I am willing to pay for hosting.&lt;/p&gt;

&lt;p&gt;1 github workflow triggered on pushes to master later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build deploy hugo&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build-deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repo with submodules&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;submodules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Hugo&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;peaceiris/actions-hugo@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;hugo-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.65.2"&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Static Site&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hugo --minify&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup AWS CLI&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chrislennon/action-aws-cli@v1.1&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to S3&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws s3 sync ./public/ s3://${{ secrets.AWS_S3_BUCKET }} --acl public-read --follow-symlinks --delete --cache-control="max-age=3600"&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ACCESS_KEY_ID }}&lt;/span&gt;
          &lt;span class="na"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_SECRET_ACCESS_KEY }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I have a website hosted at cbelsole.com where I can push content that I think would be useful for people. Total development time 1 day.&lt;/p&gt;

&lt;h1&gt;
  
  
  Future goals
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Checking all of my images to Github is eventually going to blow up the size of the repository. Eventually I want a workflow that syncs images with s3 and magically creates links.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ironically, after looking more into &lt;a href="https://stackedit.io/"&gt;stackedit.io&lt;/a&gt; it may be the CMS solution I was looking for.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>sideprojects</category>
      <category>blog</category>
    </item>
    <item>
      <title>How I decide to work on a side project</title>
      <dc:creator>Chris Belsole</dc:creator>
      <pubDate>Sat, 04 Jan 2020 18:52:45 +0000</pubDate>
      <link>https://forem.com/cbelsole/how-i-decide-to-work-on-a-side-project-22mm</link>
      <guid>https://forem.com/cbelsole/how-i-decide-to-work-on-a-side-project-22mm</guid>
      <description>&lt;h1&gt;
  
  
  How do you choose?
&lt;/h1&gt;

&lt;p&gt;Generally, I ask myself 5 things when choosing a side project.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Can this potentially make me money?&lt;/li&gt;
&lt;li&gt;Is this going to teach me something I don’t know?&lt;/li&gt;
&lt;li&gt;Is this useful to anyone?&lt;/li&gt;
&lt;li&gt;How long is this going to take?&lt;/li&gt;
&lt;li&gt;What does success look like?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The general theme here is, “Am I wasting my time?” Human life is finite and your productive years are even less. Your time and attention are the 2 greatest commodities you have as an average person. Spending them wisely on things that help you grow and improve your life should be the goal of picking your side project. As your priorities change (buying a house, raising a family, affording that lux apartment) so do your criteria of what constitutes a good use of time.&lt;/p&gt;

&lt;h1&gt;
  
  
  Consulting work
&lt;/h1&gt;

&lt;p&gt;I consider consulting work side projects since I work a full-time job. So consulting would have to be done on the side. Before I start this though I want to know it’s something I can complete in a reasonable amount of time, or if it’s a project with no clear end date is the workload light enough that I can fit it in my normal life without disrupting things too much.&lt;/p&gt;

&lt;h1&gt;
  
  
  Awesome tech stuff
&lt;/h1&gt;

&lt;p&gt;This is my favorite reason for a side project as it has not only let me play with new technologies that I would otherwise have no reason to but experimenting with something unfamiliar gives me a broader perspective on what good programming looks like and what tools are out there to solve problems. &lt;/p&gt;

&lt;p&gt;Things I’ve learned on the side include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React + Native + Hooks&lt;/li&gt;
&lt;li&gt;Rails 5&lt;/li&gt;
&lt;li&gt;Apache&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Meteor + Mongo DB (data-driven programming)&lt;/li&gt;
&lt;li&gt;Web scraping (multiple languages/frameworks. Current favorite is &lt;a href="https://github.com/puppeteer/puppeteer/"&gt;Puppeteer&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Trello (and project management in general)&lt;/li&gt;
&lt;li&gt;Bitbucket&lt;/li&gt;
&lt;li&gt;Sqlite3&lt;/li&gt;
&lt;li&gt;Vultr + Linux administration&lt;/li&gt;
&lt;li&gt;Google Cloud Platform (and to a lesser extent Azure)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main thing you want to come out of a technical project is, “What makes this technology interesting and how can I incorporate its learnings into the code I write today?” For instance, writing Rails code taught me the power of convention, working with Sqlite3 makes me rethink how I architect small projects that run on a single server, and React was immediately useful to me when our company chose to move over. I was suddenly in a position where I could take the lead on how our components were structured and the patterns/libraries that were implemented.&lt;/p&gt;

&lt;h1&gt;
  
  
  Open Source Projects/Contributions
&lt;/h1&gt;

&lt;p&gt;When I am using OSS I often want to make a contribution that adds a certain feature or browse their issue list to see if there’s something small I can knock out. To me, this is a great reason to invest some time helping to make the code you use better. It usually won’t make you money, but it’s immediately useful. The people that create these libraries usually also have a second job. So let’s all throw on our solidarity hats and solve problems together.&lt;/p&gt;

&lt;h1&gt;
  
  
  Passion projects
&lt;/h1&gt;

&lt;p&gt;These are the bane of side projects as they violate 3 of my 5 criteria right off the bat. Who knows if this thing will ever make money? Who knows if this thing will ever be useful? I haven’t even figured out the target audience yet. Success looks like not spending another 6 months typing away trying to figure out a user interaction that testers don’t hate. GLAR.&lt;br&gt;
I have spent months of my life on passion projects that never see the light of day because they never reach the level where I want to put them in the world with my name attached.&lt;/p&gt;

&lt;h1&gt;
  
  
  I can’t decide
&lt;/h1&gt;

&lt;p&gt;So you have a bunch of side projects you are looking at but you can’t decide which one to do, or you don’t have ideas but you want to do something. The trick here is to just start doing something. Getting in a routine where you open your laptop and start typing will reinforce this behavior and make it easier to start tomorrow. Abandoned side projects are a meme at this point. So don’t feel bad for tabeling something for later (or more realistically never). If you are stuck here are some ideas to jog your creativity.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Pokemon API is publicly accessible. Can you create a real Pokedex where I can point my phone at a picture of a Pokemon and have it come up?&lt;/li&gt;
&lt;li&gt;Can you scrape Craigslist for cars in the last month ordered by users’ preference that calculates the model year by how many miles per year on the car?&lt;/li&gt;
&lt;li&gt;Stretch your design skills and create a personal website from scratch that looks like something you’d want to show people.&lt;/li&gt;
&lt;/ol&gt;

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