<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: dianakw8591</title>
    <description>The latest articles on DEV Community by dianakw8591 (@dianakw8591).</description>
    <link>https://dev.to/dianakw8591</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%2F340754%2F883a3f1c-4a46-4d17-944d-eb60ceba11fb.jpeg</url>
      <title>DEV Community: dianakw8591</title>
      <link>https://dev.to/dianakw8591</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dianakw8591"/>
    <language>en</language>
    <item>
      <title>Recursion vs. Iteration in a binary tree</title>
      <dc:creator>dianakw8591</dc:creator>
      <pubDate>Fri, 21 Aug 2020 17:22:16 +0000</pubDate>
      <link>https://dev.to/dianakw8591/recursion-vs-iteration-in-a-binary-tree-48ma</link>
      <guid>https://dev.to/dianakw8591/recursion-vs-iteration-in-a-binary-tree-48ma</guid>
      <description>&lt;p&gt;When approaching an algorithm, often you have to choose between a recursive approach or an iterative approach. Although some problems or languages naturally favor one approach over another, really they can be used interchangeably. It's all a matter of understanding how to frame the problem. &lt;/p&gt;

&lt;p&gt;Both recursion and iteration run a chunk of code until a stopping condition is reached. With recursion, you repeatedly call the same function until that stopping condition, and then return values up the call stack. With iteration, rather than building a call stack you might be storing data in a particular data structure, often a stack or queue, and then running a loop that utilizes that data until the stopping condition is met. &lt;/p&gt;

&lt;p&gt;To make these ideas more concrete, here are two solutions to check if a binary tree is symmetric - one recursive and one iterative. This problem is from &lt;a href="https://leetcode.com/problems/symmetric-tree" rel="noopener noreferrer"&gt;Leetcode&lt;/a&gt; if you want to submit your own solution there! Binary trees are very conducive to recursive solutions, since each piece of a binary tree is just another binary tree. But iterative approaches can be used as well, in this case by utilizing a queue. &lt;/p&gt;

&lt;p&gt;Here's the basic problem: a binary search tree is symmetric if it is a mirror image of itself down the center. So this tree is symmetric:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F26rekuvi2bnn62kjyaxb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F26rekuvi2bnn62kjyaxb.png" alt="symmetric tree"&gt;&lt;/a&gt;&lt;br&gt;
but this tree is not:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fabx9gt68vk8eqygxdxm8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fabx9gt68vk8eqygxdxm8.png" alt="not a symmetric tree"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Tree class is already defined for us, and the &lt;code&gt;left&lt;/code&gt;, &lt;code&gt;right&lt;/code&gt;, and &lt;code&gt;val&lt;/code&gt; properties are available to use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt; &lt;span class="c1"&gt;//Definition for a binary tree node.&lt;/span&gt;
 &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;TreeNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&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;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;val&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;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;left&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;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;right&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;Given the root node of the tree, the problem is to write an algorithm to check if that tree is symmetric. Whichever approach is used, the solution needs to check that the left branch of the left branch equals the right branch of the right branch (&lt;code&gt;left.left === right.right&lt;/code&gt;) and the right branch of the left branch equals the left branch of the right branch (&lt;code&gt;left.right === right.left&lt;/code&gt;). If this condition holds for every subtree, where &lt;code&gt;left&lt;/code&gt; and &lt;code&gt;right&lt;/code&gt; are the mirror nodes of each other, than the tree is symmetric. &lt;/p&gt;

&lt;p&gt;First let's look at the recursive solution. In this solution, a sub-function takes &lt;code&gt;left&lt;/code&gt; and &lt;code&gt;right&lt;/code&gt; as arguments and compares those values, and then calls itself on the left and right children of those nodes. Here's the full implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isSymmetric&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;root&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;function&lt;/span&gt; &lt;span class="nf"&gt;compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&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="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;val&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="kc"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&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="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&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;Before calling &lt;code&gt;compare&lt;/code&gt; at all, we check if the root is even a tree. If it's not, there's no work to do. But assuming if is, we start off our recursive calls with &lt;code&gt;root.left&lt;/code&gt; and &lt;code&gt;root.right&lt;/code&gt;. First we check if both &lt;code&gt;left&lt;/code&gt; and &lt;code&gt;right&lt;/code&gt; are null, since we can't call &lt;code&gt;.left&lt;/code&gt; or &lt;code&gt;.right&lt;/code&gt; if those are not actually TreeNodes! This is one of our stopping conditions, and matching null values in the left and right position meet the criteria for a symmetric tree, so &lt;code&gt;true&lt;/code&gt; is returned up the call stack. In the next line, the conditions that violate a symmetric tree are checked. Again, since &lt;code&gt;.left&lt;/code&gt; and &lt;code&gt;.right&lt;/code&gt; cannot be called on a null value, those cases are checked first. If the values do not match, the tree is not symmetric and &lt;code&gt;false&lt;/code&gt; is returned up the call stack. Those are the two stopping conditions. Finally, if neither of those conditions are met, the &lt;code&gt;compare&lt;/code&gt; function is recursively called down each branch of the tree. The &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; ensures that both sides must return true for the outer function call to return true - if any of the inner calls resolve to &lt;code&gt;false&lt;/code&gt;, that will be passed up the call stack and the function with ultimately return &lt;code&gt;false&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;It's important to remember that in a recursive solution the inner return values must be passed up the call stack! There are no implicit returns in JavaScript, so the recursive calls of &lt;code&gt;compare&lt;/code&gt; must be explicitly returned as well. The use of &lt;code&gt;return&lt;/code&gt; is one of the key differences between the recursive and iterative solution - let's look at the iterative solution now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isSymmetric&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&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="kc"&gt;true&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;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&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;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;val&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="kc"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, the first step is to confirm we actually have a TreeNode to start. If we do, we initiate a queue with &lt;code&gt;root.left&lt;/code&gt; and &lt;code&gt;root.right&lt;/code&gt;. From there, the code logic is nearly identical to the recursive solution. The big difference is that rather than building a call stack, we are adding nodes to our queue and running the &lt;code&gt;while&lt;/code&gt; loop until the queue is empty. Another important difference is the use of &lt;code&gt;return&lt;/code&gt;. In the first condition &lt;code&gt;left === null &amp;amp;&amp;amp; right === null&lt;/code&gt;, rather than stop the loop and return &lt;code&gt;true&lt;/code&gt;, what we want is to continue checking other nodes. Returning &lt;code&gt;true&lt;/code&gt; there would break out of the loop and return &lt;code&gt;true&lt;/code&gt; from the &lt;code&gt;isSymmetric&lt;/code&gt; function immediately, since we aren't buried in a call stack. Knowing where to use &lt;code&gt;return&lt;/code&gt; and what function it is ending is key to building iterative vs recursive solutions. On the other hand, in the next condition, if a &lt;code&gt;false&lt;/code&gt; condition is found, we're done! We do want to end the &lt;code&gt;while&lt;/code&gt; loop and immediately return &lt;code&gt;false&lt;/code&gt;. Only if no &lt;code&gt;false&lt;/code&gt; condition is ever found do we hit the last line and return &lt;code&gt;true&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;I hope this provides a concrete example of moving between recursion and iteration. For me, understanding what &lt;code&gt;return&lt;/code&gt; is doing and the different stopping conditions is key to moving between these two approaches.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>recursion</category>
      <category>iteration</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Object Destructuring in JavaScript</title>
      <dc:creator>dianakw8591</dc:creator>
      <pubDate>Fri, 14 Aug 2020 18:06:50 +0000</pubDate>
      <link>https://dev.to/dianakw8591/object-destructuring-in-javascript-482k</link>
      <guid>https://dev.to/dianakw8591/object-destructuring-in-javascript-482k</guid>
      <description>&lt;p&gt;I recently found myself struggling with adding CSS classes to a React component. Once I understood the &lt;code&gt;classes&lt;/code&gt; object and how it was created, most of my confusion stemmed from basic object destructuring. So I decided to write this post to solidify my understanding of destructuring assignments in JavaScript! Hopefully it will provide some clarity for others working through this concept as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Quick Review of Objects
&lt;/h3&gt;

&lt;p&gt;An object literal in JavaScript is constructed with key, value pairs separated by a colon. Each key, value pair is separated from the next pair by a comma. Values can be any datatype - arrays, objects, strings, functions, etc - while keys must always be strings, or something that JS can convert to a string, like a number.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;myObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;myObj&lt;/code&gt;, &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; are both strings and JS gives me the shortcut of skipping writing the quotes around those. &lt;/p&gt;

&lt;p&gt;To access values of &lt;code&gt;myObj&lt;/code&gt;, I can use either dot notation or bracket notation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;myObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;
&lt;span class="c1"&gt;//1&lt;/span&gt;
&lt;span class="nx"&gt;myObj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;//1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In order to use dot notation to access an object property, the key must be a valid JavaScript identifier. From the &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/identifier"&gt;MDN web docs&lt;/a&gt;, an identifier is a "sequence of characters in the code that identifies a variable, function, or property". Importantly, an identifier cannot begin with a digit. So, if I created an object like so&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;numObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I can access values with bracket notation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;numObj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;//"a"&lt;/span&gt;

&lt;span class="nx"&gt;numObj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;//"a"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;but dot notation results in an error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;numObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="c1"&gt;// Uncaught SyntaxError: Unexpected number&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note that with bracket notation, JavaScript coerces &lt;code&gt;1&lt;/code&gt; to the string &lt;code&gt;"1"&lt;/code&gt;. However, &lt;code&gt;myObj[a]&lt;/code&gt; would result in an error - &lt;code&gt;a&lt;/code&gt; is expected to be a variable in that case.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Destructuring
&lt;/h3&gt;

&lt;p&gt;A destructuring assignment allows the mass assignment of variables to object (or array) values. Using the previous &lt;code&gt;myObj&lt;/code&gt; for example, I could assign variables to access values like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;myObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;myObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;
&lt;span class="nx"&gt;a&lt;/span&gt;
&lt;span class="c1"&gt;//1&lt;/span&gt;
&lt;span class="nx"&gt;b&lt;/span&gt;
&lt;span class="c1"&gt;//2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Or with a destructuring assignment, I can assign both those variables in one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;myObj&lt;/span&gt;
&lt;span class="nx"&gt;a&lt;/span&gt;
&lt;span class="c1"&gt;//1&lt;/span&gt;
&lt;span class="nx"&gt;b&lt;/span&gt;
&lt;span class="c1"&gt;//2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;During destructuring, I can also assign new variable names:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;second&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;myObj&lt;/span&gt;
&lt;span class="nx"&gt;first&lt;/span&gt;
&lt;span class="c1"&gt;//1&lt;/span&gt;
&lt;span class="nx"&gt;second&lt;/span&gt;
&lt;span class="c1"&gt;//2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this case, &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; are not simultaneously assigned as variables.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nested Destructuring
&lt;/h3&gt;

&lt;p&gt;Destructuring assignments can also handle nested objects. Let's start with &lt;code&gt;myNestedObj&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;myNestedObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;d&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;}}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To assign the values of &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;d&lt;/code&gt; I can destructure like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;myNestedObj&lt;/span&gt;
&lt;span class="nx"&gt;a&lt;/span&gt;
&lt;span class="c1"&gt;//1&lt;/span&gt;
&lt;span class="nx"&gt;d&lt;/span&gt;
&lt;span class="c1"&gt;//{e: 4}&lt;/span&gt;
&lt;span class="nx"&gt;b&lt;/span&gt;
&lt;span class="c1"&gt;//undefined&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this case, &lt;code&gt;b&lt;/code&gt; is a 'step' to access &lt;code&gt;d&lt;/code&gt;, and is not assigned in the destructuring. I can add the assignment of &lt;code&gt;b&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;myNestedObj&lt;/span&gt;
&lt;span class="nx"&gt;b&lt;/span&gt;
&lt;span class="c1"&gt;//{c: 3, d: {…}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Of course, I could destructure further to access &lt;code&gt;e&lt;/code&gt; and assign new variable names if I felt like it too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;outer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;d&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;inner&lt;/span&gt; &lt;span class="p"&gt;}}}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;myNestedObj&lt;/span&gt;
&lt;span class="nx"&gt;outer&lt;/span&gt;
&lt;span class="c1"&gt;//1&lt;/span&gt;
&lt;span class="nx"&gt;a&lt;/span&gt;
&lt;span class="c1"&gt;//undefined&lt;/span&gt;
&lt;span class="nx"&gt;b&lt;/span&gt;
&lt;span class="c1"&gt;//undefined&lt;/span&gt;
&lt;span class="nx"&gt;c&lt;/span&gt;
&lt;span class="c1"&gt;//3&lt;/span&gt;
&lt;span class="nx"&gt;d&lt;/span&gt;
&lt;span class="c1"&gt;//undefined&lt;/span&gt;
&lt;span class="nx"&gt;inner&lt;/span&gt;
&lt;span class="c1"&gt;//4&lt;/span&gt;
&lt;span class="nx"&gt;e&lt;/span&gt;
&lt;span class="c1"&gt;//undefined&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  The Power of Destructuring
&lt;/h3&gt;

&lt;p&gt;Destructuring is an excellent way to access the properties of an object that might be passed into a function or as the &lt;code&gt;props&lt;/code&gt; of a React component. Rather than write a line of code to assign a variable to each property, or use dot or bracket notation every time for access, objects can be destructured for code clarity and ease of writing. Destructuring can even happen in a function definition by destructuring the arguments! Overall, it's an incredibly useful concept and important to become comfortable with if you are developing in JavaScript. &lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>A Senior Dev's List of Key Unix Utilities, Explained by a Junior Dev</title>
      <dc:creator>dianakw8591</dc:creator>
      <pubDate>Fri, 07 Aug 2020 19:40:27 +0000</pubDate>
      <link>https://dev.to/dianakw8591/a-senior-dev-s-list-of-key-unix-utilities-explained-by-a-junior-dev-4bcn</link>
      <guid>https://dev.to/dianakw8591/a-senior-dev-s-list-of-key-unix-utilities-explained-by-a-junior-dev-4bcn</guid>
      <description>&lt;p&gt;If you are a developer working on a Mac, chances are you've used a Unix utility or two. At least to &lt;code&gt;cd&lt;/code&gt; around to different directories or &lt;code&gt;touch&lt;/code&gt; a new file. But chances are you haven't used the vast majority of Unix programs you have on your machine - I have 1325 on mine! Luckily, there's no need to sit down and memorize them all. What is important is to recognize the power of the Unix command line, and to know a few commands that will make your life in the terminal much easier. Below is a list of those commands. But first, a couple notes about using Unix commands in general. &lt;/p&gt;

&lt;h3&gt;
  
  
  General Rules of Unix Utilities
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Commands are lowercase&lt;/li&gt;
&lt;li&gt;Options modify the command. They are often single letters added in short form with a single dash &lt;code&gt;-&lt;/code&gt;. Some have long form options added with a double dash &lt;code&gt;--&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Options can be combined. For example, adding the &lt;code&gt;-a&lt;/code&gt; and &lt;code&gt;-l&lt;/code&gt; options to &lt;code&gt;ls&lt;/code&gt; can be written as &lt;code&gt;ls -a -l&lt;/code&gt; or &lt;code&gt;ls -al&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Commands can take arguments, often filenames&lt;/li&gt;
&lt;li&gt;Options come before filenames&lt;/li&gt;
&lt;li&gt;There must be spaces between commands, options, and filenames&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Unix Utilities to Know by Heart
&lt;/h3&gt;

&lt;h4&gt;
  
  
  ls
&lt;/h4&gt;

&lt;p&gt;Lists all your files in the current directory. There are a few important option flags to know as well. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-a&lt;/code&gt; will also show all the hidden files in a directory (those that start with a &lt;code&gt;.&lt;/code&gt;). &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-l&lt;/code&gt; will list the files in long format, showing permissions, size, and modified date&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-lh&lt;/code&gt; lists in long format with readable file size (eg 1K, 23M)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-s&lt;/code&gt; lists the allocated size of each file in blocks&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  cp &lt;em&gt;source destination&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;Copies the source to the destination. Source can be one or more files or directories. Destination is the name of the directory to copy to or the name of the new file. When copying directories, the &lt;code&gt;-r&lt;/code&gt; (or &lt;code&gt;-R&lt;/code&gt;) flag must be used. This copies recursively, and will ensure that the contents of a folder is also copied.&lt;/p&gt;

&lt;h4&gt;
  
  
  cd
&lt;/h4&gt;

&lt;p&gt;Change directory. &lt;code&gt;cd&lt;/code&gt; with no arguments will bring you to your home directory, which is represented by &lt;code&gt;~&lt;/code&gt;. You can also pass a pathname or make smaller "steps" with &lt;code&gt;cd ..&lt;/code&gt;, which will move to your parent directory. &lt;code&gt;cd&lt;/code&gt; will take relative or absolute pathnames, which can be built with &lt;code&gt;~&lt;/code&gt; (home directory), &lt;code&gt;..&lt;/code&gt; (parent directory), &lt;code&gt;.&lt;/code&gt; (current directory) and &lt;code&gt;/&lt;/code&gt; within directories. Note that if you are in a directory with a subfolder &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;cd test&lt;/code&gt; is equivalent to &lt;code&gt;cd ./test&lt;/code&gt; and both will move you into the test folder.&lt;/p&gt;

&lt;h4&gt;
  
  
  mv &lt;em&gt;source destination&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;Moves (or renames) source to destination. If the destination is an existing directory, source(s) will be moved there. &lt;/p&gt;

&lt;h4&gt;
  
  
  rm &lt;em&gt;source&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;Removes files or directories. Similarly to &lt;code&gt;cp&lt;/code&gt;, to remove directories the &lt;code&gt;-r&lt;/code&gt; or &lt;code&gt;-R&lt;/code&gt; flag must be used which will recursively removed the contents of the directory.&lt;/p&gt;

&lt;h4&gt;
  
  
  mkdir &lt;em&gt;directory&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;Create a new directory. The &lt;code&gt;-p&lt;/code&gt; flag is used to create parent directories if they don't already exist. For example, if I am in a directory with a subdirectory &lt;code&gt;test&lt;/code&gt; and want to create a director &lt;code&gt;example&lt;/code&gt; within &lt;code&gt;test&lt;/code&gt;, I could run &lt;code&gt;mkdir -p test/example&lt;/code&gt;. Since test already exists, a new folder &lt;code&gt;example&lt;/code&gt; would be created in &lt;code&gt;test&lt;/code&gt;. However, if &lt;code&gt;test&lt;/code&gt; didn't exist, the command would simply create &lt;code&gt;test&lt;/code&gt; and then create &lt;code&gt;example&lt;/code&gt; within test. Either way there are no errors.&lt;/p&gt;

&lt;h4&gt;
  
  
  grep &lt;em&gt;patterns file&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;Searches for patterns in each file, and prints each line that matches. This is a really useful command for finding other commands you've used if they are in your logs. The &lt;code&gt;-r&lt;/code&gt; flag reads files in subdirectories recursively. &lt;code&gt;-n&lt;/code&gt; adds to the output the line number in the file where the match occurred. &lt;/p&gt;

&lt;h4&gt;
  
  
  cat &lt;em&gt;filename&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;Used to view the contents of a file. With an argument of a filename, &lt;code&gt;cat&lt;/code&gt; will simply print the content of that file. Other options can be added to view only parts of the file or to write contents to a new file.&lt;/p&gt;

&lt;h4&gt;
  
  
  echo
&lt;/h4&gt;

&lt;p&gt;Displays a line of text. Most often used in scripts and other commands where you need to insert text.&lt;/p&gt;

&lt;h4&gt;
  
  
  head &lt;em&gt;filename&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;Output the first part of the file. By default, &lt;code&gt;head&lt;/code&gt; prints the first 10 lines. Useful when you only need to see the beginning of a file with lots of content.&lt;/p&gt;

&lt;h4&gt;
  
  
  tail &lt;em&gt;filename&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;Output the last part of the file. Like &lt;code&gt;head&lt;/code&gt; but for the end of the file.&lt;/p&gt;

&lt;h4&gt;
  
  
  less &lt;em&gt;filename&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;Opens a file in the terminal and allows forward and backward navigation within the file. In this mode, patterns can be searched for with &lt;code&gt;/pattern&lt;/code&gt; and using &lt;code&gt;n&lt;/code&gt; and &lt;code&gt;N&lt;/code&gt; to move backwards and forwards between matches. There are a bunch more navigation options to use as well. &lt;code&gt;q&lt;/code&gt; will exit navigation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unix Utilities to Know About
&lt;/h3&gt;

&lt;h4&gt;
  
  
  find
&lt;/h4&gt;

&lt;p&gt;Searches for files based on some user specified criteria, and returns a list of the found files. The search criteria could be pattern matching, a file type, or file name to name a few. For example, &lt;code&gt;find . -name 'test*'&lt;/code&gt; would search the current directory for filenames that started with 'test', with &lt;code&gt;*&lt;/code&gt; being a placeholder for anything that might follow. &lt;/p&gt;

&lt;h4&gt;
  
  
  curl
&lt;/h4&gt;

&lt;p&gt;A tool to transfer data to or from a server, using any of its supported protocols (FTP or HTTP for example). There are whole bunch of options for using &lt;code&gt;curl&lt;/code&gt; but know that it exists so you can search for the specifics when you need it! &lt;code&gt;wget&lt;/code&gt; is a similar command with a couple differences, mainly its ability to download recursively.&lt;/p&gt;

&lt;h4&gt;
  
  
  vim &lt;em&gt;filename&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;Opens a file with the vim text editor. Using vim is a whole other blog post, but it is a powerful tool that many developers swear by.&lt;/p&gt;

&lt;h4&gt;
  
  
  sed
&lt;/h4&gt;

&lt;p&gt;Used to perform text transformations on an input stream (a file or input from a pipeline). It can be used to search for strings in a file, update content, and replace content.&lt;/p&gt;

&lt;h4&gt;
  
  
  awk
&lt;/h4&gt;

&lt;p&gt;Another big topic, &lt;code&gt;awk&lt;/code&gt; can run programs written in the AWK language that are used to transform text in a file. &lt;code&gt;awk&lt;/code&gt; can pattern match and perform operations on matched lines, useful for file formatting.&lt;/p&gt;

&lt;h4&gt;
  
  
  pipes
&lt;/h4&gt;

&lt;p&gt;Piping is a process of sending the output of one command as the input to another. The syntax for a pipe is &lt;code&gt;|&lt;/code&gt; and information flows from left to right. So, to pipe the output of &lt;code&gt;ls&lt;/code&gt; into &lt;code&gt;less&lt;/code&gt; for example, you could write &lt;code&gt;ls | less&lt;/code&gt;, and enter the &lt;code&gt;less&lt;/code&gt; navigation with all the filenames in the directory - the output of &lt;code&gt;ls&lt;/code&gt;. &lt;/p&gt;

&lt;h4&gt;
  
  
  xargs
&lt;/h4&gt;

&lt;p&gt;Converts standard input to arguments. Useful with commands that only accept arguments and do not read standard input such as &lt;code&gt;echo&lt;/code&gt; and &lt;code&gt;rm&lt;/code&gt;. With piping, input can be piped to &lt;code&gt;xargs&lt;/code&gt; which will execute a given command for each input. A common use of this is with the &lt;code&gt;find&lt;/code&gt; command. Results of &lt;code&gt;find&lt;/code&gt; can be piped to &lt;code&gt;xargs&lt;/code&gt; to run an operation on each result, such as &lt;code&gt;rm&lt;/code&gt;. For example, to remove any file that begin with &lt;code&gt;test&lt;/code&gt;, I could write &lt;code&gt;find . -name 'test*' | xargs rm&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  And there's so much more
&lt;/h3&gt;

&lt;p&gt;The internet is your friend when it comes to learning the details of Unix utilities! Don't be afraid to play around in your terminal either and see what you can do. Hopefully this is a good start for some useful commands to know about and the basics of how to use them. Thanks for reading!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>RockOn pt 6: 5 Useful Lodash functions</title>
      <dc:creator>dianakw8591</dc:creator>
      <pubDate>Thu, 30 Jul 2020 20:53:54 +0000</pubDate>
      <link>https://dev.to/dianakw8591/rockon-pt-6-5-useful-lodash-functions-44ik</link>
      <guid>https://dev.to/dianakw8591/rockon-pt-6-5-useful-lodash-functions-44ik</guid>
      <description>&lt;p&gt;&lt;em&gt;This is the sixth and final post in my series about building &lt;a href="https://rockonapp.com"&gt;RockOn&lt;/a&gt;. Get the full background starting &lt;a href="https://dev.to/dianakw8591/rockon-pt-1-using-nokogiri-to-seed-my-database-2h05"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In last weeks &lt;a href="https://dev.to/dianakw8591/rockon-pt-5-filtering-data-3moo"&gt;post&lt;/a&gt;, I left off with an array of filtered "entry" objects. The final step is presenting stats and graphs of that data, but there's still more manipulation needed. That's where &lt;a href="https://lodash.com/"&gt;Lodash&lt;/a&gt; comes in - a Javascript library that provides a ton of useful methods for working with arrays, objects, and other data types. The collection methods can be used for both arrays and objects which is incredibly useful. Lodash has excellent documentation, but I'll share a handful of methods I found particularly useful and how to implement them.&lt;/p&gt;

&lt;p&gt;To review, here is an example of an entry object and the different keys I used to group and sort by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
 climb: {
  area_array: ["International", "Europe", "Spain", 
   "Catalonia", "…],
  climb_id: 110372,
  full_type: "Sport",
  key_type: "Sport",
  name: "La Discórdia",
  numeric_rating: 13,
  rating: "5.10"
 }
 beta: "",
 notes: "very cold and raining...",
 outcome: "Onsight",
 partners: "",
 pitches: 1,
 rack: "",
 start_date: "2019-11-23",
 style: "Lead",
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;My initial data was an array of these objects - when I use &lt;code&gt;array&lt;/code&gt; in the examples below, that is the array I'm referencing. &lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Started with Lodash
&lt;/h3&gt;

&lt;p&gt;Install Lodash in your React app with &lt;code&gt;yarn&lt;/code&gt; or &lt;code&gt;npm&lt;/code&gt;, and then import specific functions into a component like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;startCase&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;or the whole library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When the whole library is imported, functions all begin with &lt;code&gt;_.&lt;/code&gt; (&lt;code&gt;startCase&lt;/code&gt; becomes &lt;code&gt;_.startCase&lt;/code&gt;) but with cherry-picked functions you can simply call &lt;code&gt;startCase&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Useful Lodash Methods
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;_.groupBy&lt;/strong&gt;&lt;br&gt;
Takes a collection and method by which to group elements of that collection, returning an object where the keys are the result of applying that method to each element, and values are arrays of the elements that produced each key. In my case, I often wanted to group by different keys in my entry object, &lt;code&gt;start_date&lt;/code&gt; for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;groupByDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;groupBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;start_date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;groupedByDate&lt;/code&gt; is an object where the keys are every unique start date, and the values are arrays of entries that have that start date. With this function I could easily group climbs that happened on the same day! Let's say I wanted to see all the climbs from yesterday - &lt;code&gt;2020-07-29&lt;/code&gt;. I could simply call &lt;code&gt;groupByDate['2020-07-29']&lt;/code&gt; and get an array of all climbs from yesterday!&lt;/p&gt;

&lt;p&gt;By linking &lt;code&gt;_.groupBy&lt;/code&gt; methods together, I was able to easily collect all entries of a particular type, grade, and style which I used specifically to build my bar chart.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;_.maxBy&lt;/strong&gt;&lt;br&gt;
Takes a collection and a method (iteratee) invoked on each element, and returns the element that generates the maximum value when the iteratee is called. I used this method to select the hardest climb by grade on each day.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;climb.numeric_rating&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;value&lt;/code&gt; is the array of climbs on a given day - for example, &lt;code&gt;groupByDate['2020-07-29']&lt;/code&gt;. To create an array of entries that were the hardest climb done each day I combined this with...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;_.map&lt;/strong&gt;&lt;br&gt;
Similar to Javascript's built in &lt;code&gt;map&lt;/code&gt;, but can be applied to an object as well as an array. With an object, the values are the first argument passed to the iterator function - index/key and collection can also be passed. Returns an array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;maxByDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;groupByDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&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;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;climb.numeric_rating&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;_.sortBy&lt;/strong&gt;&lt;br&gt;
Similar to &lt;code&gt;groupBy&lt;/code&gt;, &lt;code&gt;sortBy&lt;/code&gt; takes a collection and the method by which to sort the elements in ascending order, returning a sorted array. Using this method I easily sorted my &lt;code&gt;maxByDate&lt;/code&gt; array into ascending order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sortBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maxByDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;start_date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This ordered array is now ready to be plotted on a time vs difficulty plot!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;_.invert&lt;/strong&gt;&lt;br&gt;
This function flips an Object's keys and values. In my case, I used it to transform my maps for converting Yosemite Decimal System climbing grades to numeric grades that were easier to implement in my graphs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;yds_conversion&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5.7&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5.8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5.9&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5.10&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5.10-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5.10+&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5.10a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5.10b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5.10c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5.10d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;14&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;But I often had to map both ways, and &lt;code&gt;invert&lt;/code&gt; allowed me to easily build the reverse mapping hash. Note that when keys are repeated, later values override earlier values. So when &lt;code&gt;yds_conversion&lt;/code&gt; is inverted, the key &lt;code&gt;14&lt;/code&gt; will have the value &lt;code&gt;"5.10d"&lt;/code&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  That's just the beginning...
&lt;/h3&gt;

&lt;p&gt;Lodash has a rich library of functions that go way beyond Javascript's built in libraries. Again, their documentation is great, so don't be afraid to dive in and try some out!&lt;/p&gt;

&lt;p&gt;That brings us to the end of my series about &lt;a href="https://rockonapp.com"&gt;RockOn&lt;/a&gt;. Hopefully there have been some useful bits along the way, and thanks for reading!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>RockOn pt 5: Filtering Data</title>
      <dc:creator>dianakw8591</dc:creator>
      <pubDate>Fri, 24 Jul 2020 18:15:47 +0000</pubDate>
      <link>https://dev.to/dianakw8591/rockon-pt-5-filtering-data-3moo</link>
      <guid>https://dev.to/dianakw8591/rockon-pt-5-filtering-data-3moo</guid>
      <description>&lt;p&gt;&lt;em&gt;This is the fifth post in my series about building &lt;a href="https://rockonapp.com"&gt;RockOn&lt;/a&gt;. Get the full background starting &lt;a href="https://dev.to/dianakw8591/rockon-pt-1-using-nokogiri-to-seed-my-database-2h05"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We've made it to the point in RockOn where the user has entered some of their ascents and has a couple data points saved. What now? Well, a bunch of graphs and filter options of course! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FQq8n-td--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4w2llwapue033csbhqta.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FQq8n-td--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4w2llwapue033csbhqta.png" alt="stats page view of RockOn"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In broad strokes, a user's entries are fetched from the database and passed through a filtering function that is controlled by the user. That filtered array is then passed to the graphs and logbook so that only ascents that meet the selected criteria are displayed. Here's a better view of all those filter options:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--c4f-o6Hn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r5bkmab9yvemae6d0o2s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c4f-o6Hn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r5bkmab9yvemae6d0o2s.png" alt="filter options"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's a lot of climbing terminology in there but don't let that dissuade you. You can think of these options just like filters for a house search on Zillow: are you looking to rent or buy? What square footage and number of bathrooms do you want? Is in-unit laundry a must have? Yes, rock climbing is just like searching for your next apartment. &lt;/p&gt;

&lt;p&gt;Let's break this down and start from the beginning. When a user logs in, all of their entries are fetched from the back end and saved in state to be passed to other components as needed. The entries come as an array of objects - here's an example of an entry object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
 climb: {
  area_array: ["International", "Europe", "Spain", 
   "Catalonia", "…],
  climb_id: 110372,
  full_type: "Sport",
  key_type: "Sport",
  name: "La Discórdia",
  numeric_rating: 13,
  rating: "5.10"
 }
 beta: "",
 notes: "very cold and raining...",
 outcome: "Onsight",
 partners: "",
 pitches: 1,
 rack: "",
 start_date: "2019-11-23",
 style: "Lead",
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This object has all the information needed for the graphs and logbooks, and most of the keys are filterable. We'll walk through the process of filtering by outcome - the many ways that climbers describe whether they fell off the climb at some point, or whether they held on until the top. Again, don't worry about the terminology too much - just know that only one outcome can be applied to a given entry.  &lt;/p&gt;

&lt;p&gt;In the filter options, everything begins as selected. In the case of outcomes, that means that entries with any of the nine outcome options attached will be displayed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bmdizyg7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jljwfiyapy0xkr4hh2l7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bmdizyg7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jljwfiyapy0xkr4hh2l7.png" alt="outcome filter options"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All of the filter options are just part of a controlled form!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Group&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;Form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Select outcomes:&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Label&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="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`inline-checkbox`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mb-3"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;mappingRopeOutcomes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;key&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="nc"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Check&lt;/span&gt; &lt;span class="na"&gt;inline&lt;/span&gt;
       &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt;
       &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleOutcomeToggle&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
       &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
       &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
       &lt;span class="na"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;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;Form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Group&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;span&lt;/code&gt; surrounding each check box is simply for styling purposes, but the functionality of the form follows the same pattern as discussed in &lt;a href="https://dev.to/dianakw8591/rockon-pt-4-controlled-forms-in-react-529l"&gt;last week's post&lt;/a&gt;. Any change to the form is handled by the &lt;code&gt;handleOutcomeToggle&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleOutcomeToggle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;target&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;setOutcome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&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="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This function in turn updates state using &lt;code&gt;setOutcome&lt;/code&gt; and simply flips the boolean from what it was before. The &lt;code&gt;Stats&lt;/code&gt; component where these functions live is functional, so I am using the &lt;code&gt;useState&lt;/code&gt; hook to save and set my outcomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setOutcome&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="p"&gt;({&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Onsight&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Flash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Redpoint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Pinkpoint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tronsight&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No Falls&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TR Attempt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Repeat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Attempt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Rather than having a &lt;code&gt;useState&lt;/code&gt; hook for every outcome possibility like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;onsight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setOnisght&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="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I can use one hook that handles the entire object, and update each key of the object appropriately by looking at the &lt;code&gt;target.name&lt;/code&gt; that comes from my form. Nifty!&lt;/p&gt;

&lt;p&gt;So following this flow, if I don't want to see any of my climbs with an outcome of 'Onsight', I unselect that checkbox, which changes the value of &lt;code&gt;outcome.Onsight&lt;/code&gt; to false. &lt;/p&gt;

&lt;p&gt;Next I need a way to use state to filter out any climbs from the entry array that have an outcome of &lt;code&gt;Onsight&lt;/code&gt;. I'm sure there are lots of ways to solve this filtering problem (and quite a few different helper function to use, both built into Javascript or from outside libraries like &lt;a href="https://lodash.com/"&gt;Lodash&lt;/a&gt;) but I'll share my original solution here. In the first step I built an array of outcomes that only included the ones selected, where the value is true.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;outcomeArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here &lt;code&gt;Object.keys(outcome)&lt;/code&gt; is an array of the outcome keys.  The filter removes any keys that have false values in the original &lt;code&gt;outcome&lt;/code&gt; object. &lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;outcomeArray&lt;/code&gt;, I then filtered my entries array such that only entries with outcomes included in the &lt;code&gt;outcomeArray&lt;/code&gt; are kept:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;outcomeArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The filtered array is then passed to the graphs and logbook components, so that as a user select filters the displays are updated in real time. &lt;/p&gt;

&lt;p&gt;This is the same flow I followed for all of the filter options - dates, grades, style, etc. Some of those data types took a bit more manipulation or a slightly different method to achieve the filter but the concept is the same. Finally, by stringing the filter functions together, I was able to apply all of the filters at once. Here's that final function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filtered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;entries&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;moment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;start_date&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;moment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;moment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;start_date&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;moment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;typeArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;climb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key_type&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;climb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key_type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Boulder&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;styleArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;outcomeArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;climb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;numeric_rating&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;grade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;low&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;climb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;numeric_rating&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;grade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;high&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To plot the &lt;code&gt;filtered&lt;/code&gt; array even more manipulation is needed - I'll dive into that next week in part 6. Have a great weekend and thanks for reading!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>RockOn pt 4: Controlled Forms in React</title>
      <dc:creator>dianakw8591</dc:creator>
      <pubDate>Fri, 17 Jul 2020 18:23:13 +0000</pubDate>
      <link>https://dev.to/dianakw8591/rockon-pt-4-controlled-forms-in-react-529l</link>
      <guid>https://dev.to/dianakw8591/rockon-pt-4-controlled-forms-in-react-529l</guid>
      <description>&lt;p&gt;&lt;em&gt;This is the fourth post in my series about building &lt;a href="https://rockonapp.com"&gt;RockOn&lt;/a&gt;. Get the full background starting &lt;a href="https://dev.to/dianakw8591/rockon-pt-1-using-nokogiri-to-seed-my-database-2h05"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In my previous posts I discussed all the work that went into seeding my database and building a search interface - now we've arrived at the point where a user is finally entering information about a particular ascent. Let's say our user has just climbed the iconic Exum Ridge in Grand Teton National Park. Here's the form they'd see after selecting that climb:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_O6mDdUB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/icbyeczdkyewyehehxg9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_O6mDdUB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/icbyeczdkyewyehehxg9.png" alt="climbing log form"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's walk through this. The first thing the user selects is the date, which can be selected from a dropdown calendar. I used the &lt;code&gt;react-date-picker&lt;/code&gt; component for this which was easy to set up and integrate, once I got the date formatting correct (I highly recommend using &lt;a href="https://momentjs.com/"&gt;moment&lt;/a&gt; for handling dates in Javascript).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aAYzemW9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vx0mv8z0sggbxlo91ppw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aAYzemW9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vx0mv8z0sggbxlo91ppw.png" alt="dropdown calendar view"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next field, pitches, or how many rope lengths long a climb is, is autofilled from the route data. This field is modifiable by the user in the event that they have combined pitches and want to record the actual number that they climbed, or if the data from Mountain Project is incorrect. The 'Style' and 'Outcome' fields have dropdown menus to choose from, and the last four fields are just text fields for the user to type their notes into.&lt;/p&gt;

&lt;p&gt;So for my eight fields, how many &lt;code&gt;handleChange&lt;/code&gt; functions did I need for handling user input? On first glance, it might seem like each field requires its own function. But in my case, I just needed two. All the fields have the same structure, except for the date picker component which was easiest to handle with its own dedicated function. Before getting into the code, a quick review of controlled forms.&lt;/p&gt;

&lt;p&gt;From the official &lt;a href="https://reactjs.org/docs/uncontrolled-components.html#:~:text=In%20a%20controlled%20component%2C%20form,form%20values%20from%20the%20DOM."&gt;React documentation&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In a controlled component, form data is handled by a React component. The alternative is uncontrolled components, where form data is handled by the DOM itself.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What this means in practice is that when the user enters input in a controlled form, React state is updated. That state then controls the value of the form. In this way a single source of truth is retained, managed by state.&lt;/p&gt;

&lt;p&gt;To actually code this, there are three parts to consider: state, the &lt;code&gt;handleChange&lt;/code&gt; function, and the form field itself. To begin, I set the state of all the fields. In my class based component, that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&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;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;pitches&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;climb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pitches&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="na"&gt;start_date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;partners&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;beta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;rack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;:&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;where the &lt;code&gt;error&lt;/code&gt; state is used to display error messages on a failed form submittal. &lt;/p&gt;

&lt;p&gt;My form fields all look essentially the same, where &lt;code&gt;name&lt;/code&gt; denotes what the field is for and corresponds to the correct key in state, &lt;code&gt;value&lt;/code&gt; is controlled by the corresponding state, and all of the &lt;code&gt;onChange&lt;/code&gt; functions are the same and pass &lt;code&gt;event&lt;/code&gt; as the argument. Here's the form field for partners (using Bootstrap React components):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Control&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"partners"&lt;/span&gt;
    &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;event&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;handleChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;value&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;partners&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;onChange&lt;/code&gt; is written as a callback here, but &lt;code&gt;onChange={this.handleChange}&lt;/code&gt; would do the same thing.&lt;/p&gt;

&lt;p&gt;By formatting all of my fields with the same structure, I was able to use one &lt;code&gt;handleChange&lt;/code&gt; function for (almost all) of my fields. The &lt;code&gt;event&lt;/code&gt; itself contained all the information I needed to update the appropriate state!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;  &lt;span class="nx"&gt;handleChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&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;newFields&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;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="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&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;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newFields&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So in the case of updating the partners field, the spread operator will first populate my &lt;code&gt;newFields&lt;/code&gt; object with all of the existing key/value pairs in &lt;code&gt;state.fields&lt;/code&gt;. Because of the order, whatever &lt;code&gt;[e.target.name]&lt;/code&gt; evaluates to will override any key that comes before it in the object. In the case of partners, &lt;code&gt;[e.target.field]&lt;/code&gt; evaluates to just that, partners, with whatever the user has typed (&lt;code&gt;e.target.value&lt;/code&gt;) as the new value, and resets whatever was previously the value of &lt;code&gt;partners&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;It's important to remember that in Javascript, object keys are always strings. To save some typing, Javascript automatically converts keys to strings, like in my original state object. I haven't bothered to put quotes around the keys, (&lt;code&gt;fields:&lt;/code&gt; rather than &lt;code&gt;"fields":&lt;/code&gt;) but Javascript is reading the keys as strings anyways. In the case of &lt;code&gt;e.target.value&lt;/code&gt;, I want the key to be whatever that &lt;strong&gt;evaluates&lt;/strong&gt; to, not the string &lt;code&gt;"e.target.value"&lt;/code&gt;. The brackets tell Javascript to do just that. &lt;/p&gt;

&lt;p&gt;The only field that didn't follow this format was the date. That component supplied the new date as the argument to its &lt;code&gt;onChange&lt;/code&gt; function rather than the event, so I chose to write a separate &lt;code&gt;handleDateChange&lt;/code&gt; function and handle that case.&lt;/p&gt;

&lt;p&gt;By having all of my form fields follow the same structure, I saved myself a lot of repeat code. Another place where I implemented the same tactic was building my dropdown menus for the 'Style' and 'Outcome' fields. All my options needed to be wrapped in &lt;code&gt;&amp;lt;option&amp;gt;&lt;/code&gt; tags, and I also had multiple 'Outcome' lists depending on the type of climb that was being recorded. To save some typing, I simply created arrays of 'Style' and 'Outcome' choices, and then mapped those values into a new array of &lt;code&gt;&amp;lt;option&amp;gt;&lt;/code&gt; tags that I used in the form itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;  &lt;span class="nx"&gt;createOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;option&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;By setting the value of each option this way, I was able to use the same &lt;code&gt;handleChange&lt;/code&gt; function described above.&lt;/p&gt;

&lt;p&gt;On form submittal, all of the information I need to send to my back end is already saved in state and formatted correctly. Once I post successfully, I clear most of my form values using state, except for the date to allow easy entry of another climb on the same day!&lt;/p&gt;

&lt;p&gt;Now that a user has some data entered, what actually happens with that data? Next week I'll dive into the graphs and logbook entries I use to give users an easy way to view and manipulate their own data.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>RockOn pt 3: Handling Hierarchical Areas</title>
      <dc:creator>dianakw8591</dc:creator>
      <pubDate>Sat, 11 Jul 2020 18:56:23 +0000</pubDate>
      <link>https://dev.to/dianakw8591/rockon-pt-3-handling-hierarchical-areas-52hd</link>
      <guid>https://dev.to/dianakw8591/rockon-pt-3-handling-hierarchical-areas-52hd</guid>
      <description>&lt;p&gt;&lt;em&gt;This is the third post in my series about building &lt;a href="https://rockonapp.com"&gt;RockOn&lt;/a&gt;. &lt;a href="https://dev.to/dianakw8591/rockon-pt-2-searching-with-ransack-3l7h"&gt;Previously&lt;/a&gt; I discussed the implementation of route name search, and further background is &lt;a href="https://dev.to/dianakw8591/rockon-pt-1-using-nokogiri-to-seed-my-database-2h05"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Last week I discussed my process for implementing a search by route name in RockOn and why I felt that it was a key component of the user experience. Another common scenario I wanted to account for was the case when multiple routes are completed at the same crag or area. Imagine going to your local rock outcropping and climbing five routes there. Would you rather have to type in each route name to  make your entries, or search for "local rock outcropping" and then quickly select the routes you did from the list that was returned? &lt;/p&gt;

&lt;h3&gt;
  
  
  The User Experience
&lt;/h3&gt;

&lt;p&gt;The most immediate challenge when thinking about areas is that all of them are different sizes! An area like Yosemite has 2,000+ routes nested under it, too many for a dropdown. I considered a series of nested searches, where a search for a high-up parent area would then provide a dropdown of all its children areas, until eventually reaching the specific crag containing only routes. This would have been complicated to build and likely a poor user experience if many levels of areas had to be navigated. Beyond that, the lowest levels of Mountain Project area designations are often extremely vague, such as "west face" or "southeast group", and don't correspond to common crag names that climbers know. I could have stopped one level up and never returned the lowest level "leaf" areas, but that algorithm isn't one size fits all. Many leaf areas are common crag designations and a level up is too general and expansive.&lt;/p&gt;

&lt;p&gt;With all of this in mind, I ultimately chose to implement an area search that leads to an autocomplete-style search of all the nested routes under that area. The first step from a user perspective is to search by area name. This search is accomplished in exactly the same way as the route name search is, by using Ransack and returning a list of areas to choose from. But while selecting a route name opens a form to complete about the ascent, selecting an area results in another fetch to the back end for all the subroutes. &lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a Self Join
&lt;/h3&gt;

&lt;p&gt;Before I dive into that code, it's useful to understand the structure of the area table in the database. I created it with a parent/child hierarchy structure, and ActiveRecord provides some useful associations for this self join. My case was nearly identical to the manager/subordinate example given in the &lt;a href="https://guides.rubyonrails.org/association_basics.html#self-joins"&gt;Ruby on Rails docs&lt;/a&gt; where a parent area (manager) can have many children (subordinates) but any child can only have one parent. The relationships defined in my area model simply reference the same model with the &lt;code&gt;class_name&lt;/code&gt; key, and &lt;code&gt;parent_id&lt;/code&gt; is the foreign key such that each child keeps track of its parent. Here's my code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Area&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;class_name: &lt;/span&gt;&lt;span class="s2"&gt;"Area"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;foreign_key: :parent_id&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;class_name: &lt;/span&gt;&lt;span class="s2"&gt;"Area"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;optional: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:climbs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;By defining my relationships like this, I now had access to &lt;code&gt;parent&lt;/code&gt; and &lt;code&gt;children&lt;/code&gt; methods for my Area class. Thanks Ruby! Also note that there is nothing in my models to restrict an area from having both subareas and associated routes. Mountain Project enforces this either/or on their end, so I got to seed my database knowing this was the case.&lt;/p&gt;

&lt;h3&gt;
  
  
  All of the Subroutes
&lt;/h3&gt;

&lt;p&gt;Armed with these methods, I was then able to write a function that would return all the routes nested below an area regardless of the area 'level'. Conceptually, I wanted a method that did something like this: if an area has children areas, check all children areas. If an area has climbs, return the climbs. If this sounds like a perfect place for recursion to you, that was my thought as well, and Ruby makes the code deceptively simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;all_child_routes&lt;/span&gt;
    &lt;span class="n"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all_child_routes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;climbs&lt;/span&gt;
    &lt;span class="n"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatten&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let's walk through this. &lt;code&gt;all_child_routes&lt;/code&gt; is an instance method of the &lt;code&gt;Area&lt;/code&gt; class, so &lt;code&gt;children&lt;/code&gt; and &lt;code&gt;climbs&lt;/code&gt; are both methods called on the specific area. In the first line, &lt;code&gt;routes&lt;/code&gt; is defined as an array, simply because &lt;code&gt;map&lt;/code&gt; always returns an array. This also takes advantage of the fact that when &lt;code&gt;children&lt;/code&gt; is called on an area that has no children an empty array will be returned (rather than &lt;code&gt;nil&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;). As the call stack resolves,  &lt;code&gt;climbs&lt;/code&gt; are pushed onto the &lt;code&gt;routes&lt;/code&gt; array, which creates an array of arrays. (Similarly to &lt;code&gt;children&lt;/code&gt;, &lt;code&gt;climbs&lt;/code&gt; called on area that has no climbs returns an empty array so we don't have to worry about &lt;code&gt;nil&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt; ending up in the &lt;code&gt;routes&lt;/code&gt; array). The final line returns a flattened array, which is ultimately what we want. This code actually handles the situation where areas have both subareas and routes, although that should never be the case. &lt;/p&gt;

&lt;p&gt;Here's another way to write this method that's a little wordier and does depend on areas never having both subareas and climbs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;all_child_routes&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;children&lt;/span&gt;
     &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all_child_routes&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;flatten&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;climbs&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;They key is to keep the arrays from becoming deeply nested, which &lt;code&gt;flatten&lt;/code&gt; takes care of.&lt;/p&gt;

&lt;p&gt;With these few lines of code, I was then able to return all the climbs of all the subareas of any given area!&lt;/p&gt;

&lt;h3&gt;
  
  
  Selecting the Climb
&lt;/h3&gt;

&lt;p&gt;Back on the front end, I implemented a React component that handled autosuggestion with simple text matching. I imported &lt;code&gt;react-autosuggest&lt;/code&gt; and customized the &lt;code&gt;Autosuggest&lt;/code&gt; component for my particular case. The meat of the autosuggest is in the &lt;code&gt;getSuggestions&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getSuggestions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inputValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&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;inputLength&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;inputValue&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;inputLength&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="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;autoList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;climb&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;climb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inputLength&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;inputValue&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;where &lt;code&gt;value&lt;/code&gt; is the user input in the text field, and &lt;code&gt;autoList&lt;/code&gt; is the list of climbs that was returned from my previous code. The returned array of climb names is displayed in a dropdown, and when a user selects their climb of choice, the ascent details form pops up the same as if the search had begun with the climb name in the first place.&lt;/p&gt;

&lt;p&gt;This text matching leaves a lot of room for greater sophistication, such as ignoring special characters and matching substrings that don't start from the beginning of the climb name. In some cases it would also be useful to see the full dropdown of climbs without typing any characters, but as discussed above this list would have to curated to avoid including thousands of entries. Improving this portion of the user experience is high on my list of upgrades to make to RockOn!&lt;/p&gt;

&lt;p&gt;All together now:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--F2C_BQBO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2ghhaxaqvx278q7ozbb7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F2C_BQBO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2ghhaxaqvx278q7ozbb7.gif" alt="GIF of user searching for area 'el cap'"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  More Fun with Areas
&lt;/h3&gt;

&lt;p&gt;While we're on the subject of areas, I also ran into a case where I wanted to find the lowest common ancestor of a set of climbs. To be exact, I wanted to list the most specific area possible for a given day of climbing. Remember, given the extreme specificity of leaf areas on Mountain Project, routes that are a five minute stroll apart can actually be classified in different areas, never mind the case of climbing routes that are truly at separate crags. In one of my log views, climbs are grouped by date, and I wanted to list the area that was visited that day as specifically as possible.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mGdERUqM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xz77npofppq43o58rybp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mGdERUqM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xz77npofppq43o58rybp.png" alt="Logbook entry with climbs from unique areas"&gt;&lt;/a&gt;&lt;em&gt;These three climbs are found at two distinct crags but are most closely connected by Tuolumne Meadows.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I accomplished the search for most specific common ancestor by looping through the set of entries' area arrays until I found an ancestor that diverged. Helpfully, Mountain Project's API returns an array of parent areas with the climb object, ordered from least specific to most specific, so that data was already available to me. Here's my code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;commonArea&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;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="k"&gt;while&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;minLength&lt;/span&gt;&lt;span class="p"&gt;)&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;first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// found is looking for the first area that is not the same as areas get more specific&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;found&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;areaArrays&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;areas&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;let&lt;/span&gt; &lt;span class="nx"&gt;area&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;areas&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="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;first&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;area&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;first&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;area&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;found&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;return&lt;/span&gt; &lt;span class="nx"&gt;areaArrays&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &amp;gt; &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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here &lt;code&gt;minLength&lt;/code&gt; is the length of the shortest area array in question, and &lt;code&gt;areaArrays&lt;/code&gt; is an array of all the area arrays that are being searched for common ancestry. The &lt;code&gt;while&lt;/code&gt; loop breaks when an area doesn't match the first area on that 'level' or when the shortest area array has been fully traversed (&lt;code&gt;i &amp;gt; minLength&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;The area structure provided some opportunities for writing interesting and challenging code and presents plenty of further opportunities for refining the user search experience. &lt;/p&gt;

&lt;p&gt;Next week I'll dive into what happens when a climb has finally been chosen: the ascent logging form!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>RockOn pt 2: Searching with Ransack</title>
      <dc:creator>dianakw8591</dc:creator>
      <pubDate>Fri, 03 Jul 2020 17:48:33 +0000</pubDate>
      <link>https://dev.to/dianakw8591/rockon-pt-2-searching-with-ransack-3l7h</link>
      <guid>https://dev.to/dianakw8591/rockon-pt-2-searching-with-ransack-3l7h</guid>
      <description>&lt;p&gt;&lt;em&gt;This is the second post in my series about building &lt;a href="https://rockonapp.com"&gt;RockOn&lt;/a&gt;. For more background and to read about how I seeded my database head &lt;a href="https://dev.to/dianakw8591/rockon-pt-1-using-nokogiri-to-seed-my-database-2h05"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A key part of RockOn's user experience (and why I went through the effort of seeding my own database) is the ability for a user to easily find a rock climb. Ideally, this means that a user can type in part of a route name, forgetting the articles and misspelling the main content, and still be returned the route they were looking for. I also wanted a user to be able to search by route name or area name. The area search presented a lot more challenges from a UX perspective, so I began by just building the search by route name. &lt;/p&gt;

&lt;p&gt;Building the full text search myself was outside the scope of this project, but luckily other people have solved this problem already and made their solutions freely available on the internet! After a bit of research, I chose to use the gem &lt;a href="https://github.com/activerecord-hackery/ransack"&gt;Ransack&lt;/a&gt; for its popularity and ease of implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Ransack
&lt;/h3&gt;

&lt;p&gt;As usual it's easy to get started with the Ransack gem. In your gemfile, add &lt;code&gt;gem 'ransack'&lt;/code&gt; and run &lt;code&gt;bundle install&lt;/code&gt;. The search I wanted to implement was very straightforward: search the 'name' column in the 'climbs' table with the query parameter and return the results. This is very similar to the first example in the Ransack documentation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
  &lt;span class="vi"&gt;@q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ransack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:q&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="vi"&gt;@people&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;distinct: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;:q&lt;/code&gt; is the search term. To search just the 'name' column, I used one of Ransack's search matcher predicates (also outlined in the docs):&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YH2B5-17--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2o6fwzn8ykm3ffw4lp8h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YH2B5-17--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2o6fwzn8ykm3ffw4lp8h.png" alt="Ransack documentation for case insensitive search"&gt;&lt;/a&gt;&lt;br&gt;
I called another method on the returned search object to limit the total returned climbs, and then returned a JSON object as usual. Here's the whole five lines of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
    &lt;span class="vi"&gt;@q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Climb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ransack&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;name_i_cont: &lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:q&lt;/span&gt;&lt;span class="p"&gt;]})&lt;/span&gt;
    &lt;span class="n"&gt;climbs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;distinct: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;climbs: &lt;/span&gt;&lt;span class="n"&gt;climbs&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Overall very easy to implement, and Ransack provides great documentation for more complex searching as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ransack Behind the Scenes
&lt;/h3&gt;

&lt;p&gt;What is Ransack actually doing when I call it on my model? More specifically, what are the SQL statements that are executed?&lt;/p&gt;

&lt;p&gt;By enabling the ActiveRecord logger in the Rails console, I can see the SQL statements that are run by Ransack. In this case, it's pretty simple. Running these Ransack methods&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="vi"&gt;@q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Climb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ransack&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;name_i_cont: &lt;/span&gt;&lt;span class="s2"&gt;"nose"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="vi"&gt;@q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;generates this SQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="nv"&gt;"climbs"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;"climbs"&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="nv"&gt;"climbs"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;"name"&lt;/span&gt; &lt;span class="k"&gt;ILIKE&lt;/span&gt; &lt;span class="s1"&gt;'%nose%'&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The key to Ransack's search here is using SQL's &lt;code&gt;ILIKE&lt;/code&gt; operator which matches on similar values rather than exact ones. &lt;code&gt;ILIKE&lt;/code&gt; versus &lt;code&gt;LIKE&lt;/code&gt; is just case insensitive. The &lt;code&gt;%&lt;/code&gt; surrounding my search query &lt;code&gt;"nose"&lt;/code&gt; is a wildcard and represents any character or set of characters. &lt;/p&gt;

&lt;h3&gt;
  
  
  The Query Parameter
&lt;/h3&gt;

&lt;p&gt;Now that my back end search functionality was taken care of, I needed to write the front end API call that passed along my search query. In this case I was making a GET request, so my query parameter would be in the url. For this method it was useful to use Javascript's URL object that gave me access to methods that help build and validate urls. Here's the code I used to build my url, where &lt;code&gt;route&lt;/code&gt; is the name of route entered by the user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API_ROOT&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/climbs`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;q&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is equivalent to writing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API_ROOT&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/climbs?q=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;but using the URL methods helps avoid syntax errors and validates the url. With that, I just made a simple fetch request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Putting it All Together
&lt;/h3&gt;

&lt;p&gt;With one gem and a couple of functions, I was able to give my users a pretty easy search experience.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TehIDVRm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/i0k00lkev3zbtygm50be.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TehIDVRm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/i0k00lkev3zbtygm50be.gif" alt="GIF of user searching for 'nose'"&gt;&lt;/a&gt;&lt;br&gt;
There are certainly improvements that can be made, such as handling misspelled words and providing a 'See More' option if the climb of choice isn't one of the first eight results. But so far I've found that armed with the general idea of the route name, my search will usually return exactly what I want.&lt;/p&gt;

&lt;p&gt;Next week I'll go through the challenges of searching by area and some of the methods I built for handling my hierarchical area structure.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>RockOn pt. 1: Using Nokogiri to Seed my Database</title>
      <dc:creator>dianakw8591</dc:creator>
      <pubDate>Fri, 26 Jun 2020 21:11:03 +0000</pubDate>
      <link>https://dev.to/dianakw8591/rockon-pt-1-using-nokogiri-to-seed-my-database-2h05</link>
      <guid>https://dev.to/dianakw8591/rockon-pt-1-using-nokogiri-to-seed-my-database-2h05</guid>
      <description>&lt;p&gt;As my final project for Flatiron School's software development program I chose a topic near and dear to my heart: rock climbing. My previous job had been as a climbing ranger in Yosemite, and I've invested years in the sport and traveled all over the world for it. I was actually in Spain climbing (where this cover photo was taken) while I was applying to software engineering programs. On rest days I'd practice programming fundamentals and work through pre-coursework for bootcamps. I would also take careful notes about all the climbing I was doing, something I've done for years. It's not uncommon for climbers to keep a logbook or journal, whether in paper or spreadsheet format, and it's a nice way to mark accomplishments, keep notes and track progress. Here's my entry from the cover photo day, the last climb of the trip on Pa Ella y Pa los Guiris:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OyIZfSUt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8syilb46yfx903mel35g.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OyIZfSUt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8syilb46yfx903mel35g.jpg" alt="Log entry with climbs, grades and dates"&gt;&lt;/a&gt;&lt;em&gt;Not super legible is it?&lt;/em&gt;&lt;br&gt;
But here's the problem with my current logbook: I can hardly read my handwriting! Never mind if I'm curious about how many days I've climbed in a year, or how many routes I've climbed of a certain type or grade. That's a lot of time spent going through and adding up all of my entries by hand! &lt;/p&gt;

&lt;p&gt;Thus the concept for my final project: a digital climbing logbook that allows climbers to easily enter new climbs and visualize their climbing history. I'll talk about the data visualization in a later post, but in this post I'll discuss the first major hurdle I encountered: how to give a user easy access to information about a specific rock climb. &lt;/p&gt;

&lt;p&gt;For any given ascent, there are some 'subjective' features and some 'objective' features. Subjective features include information like did you fall or not, and any notes about your experience on the climb. Objective features are things like grade (how hard the route is) and length. That's the type of information that can be found in a guidebook, and while there can be intense debate in the community about a some of these objective features, particularly grade, it's information that is inherent to a given climb. Therefore, I did not want my users to have to manually enter names, grades, and lengths for every ascent. Rather, they should be able to select that information from a database and only enter information specific to their experience on the climb. &lt;/p&gt;

&lt;p&gt;Thankfully, this information is freely available on the internet in the form of &lt;a href="https://www.mountainproject.com/"&gt;Mountain Project&lt;/a&gt;. For North American rock climbing particularly, Mountain Project's database is quite thorough, and they offer an API to access route and area information. However, their API only has endpoints for route IDs or latitude, longitude coordinates, and I wanted users to be able to search for routes by name. I couldn't use the route ID endpoint from my front end because a user has no idea what a given climb's ID is! I considered using a map where the user could select a point near their climbing location, and using that coordinate I could return a list of climbs from Mountain Project within a certain radius. That might have worked well in some scenarios, but in areas with thousands of climbs, a coordinate is not specific enough for an easy search experience through the returned list. Plus, locating a climbing area on a map is just not as easy as typing in a route name! Ultimately, I decided that in order to provide the best user experience, I needed to seed my own database and allow a user to search that by route name or area name.&lt;/p&gt;

&lt;p&gt;My end goal was to make the entirety of Mountain Project searchable in my own database, which meant first getting every route ID. Enter Nokogiri, an HTML (as well as XML, SAX, and Reader) parser. If I could figure out where the route IDs existed in the HTML structure of Mountain Project's pages, I could open each page with Open-URI (another module that ships with Ruby) and use Nokogiri's CSS and HTML selectors to access the IDs.&lt;/p&gt;

&lt;p&gt;Nokogiri is a dependency in every Rails project, so it's extremely easy to get started. I simply required Open-URI at the top of my file, and then used Open-URI and Nokogiri together like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'open-uri'&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Nokogiri&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;url&lt;/code&gt; is the url of the page I wanted to parse. Now that I had access to the HTML, I just needed to use the right selectors to get the information I was interested in - mainly area name and ID and route ID.&lt;/p&gt;

&lt;p&gt;Mountain Project's information is structured hierarchically with areas containing sub-areas or routes but never both. Therefore, my general strategy was to start at a high-level area page. If that page contained sub-areas, I would recursively go through each of those. If an area contained routes, I would grab the route IDs.&lt;/p&gt;

&lt;p&gt;Let's walk through my code for an area page: &lt;a href="https://www.mountainproject.com/area/105833381/yosemite-national-park"&gt;Yosemite National Park&lt;/a&gt;. The name of the area is a big header at the top, and it's easy to find the &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; I'm looking for in the HTML with Chrome's developer tools:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NWZ_VIus--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/987a7rlltlfar256nx7a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NWZ_VIus--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/987a7rlltlfar256nx7a.png" alt="Mountain Project's Yosemite page with corresponding HTML"&gt;&lt;/a&gt;&lt;br&gt;
To select the inner text of that particular header I consulted Nokogiri's documentation for available methods and used a fair amount of trial and error. My final code looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'h1'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;children&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;.css&lt;/code&gt; means I'm using CSS selectors, in this case selecting &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; tags. That query returns a node set, similar to an array, from which I want 0th item. From there I want the first child text and to remove any leading or trailing whitespace characters. With the name string successfully selected, I create a new Area entry in my own database.&lt;/p&gt;

&lt;p&gt;At this point I need to check if the area contains sub-areas or routes. Sub-areas are identified by a class of &lt;code&gt;left-nav-row&lt;/code&gt; as seen here:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0TqxWvHW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/22uk7uumo6vwapgpokpq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0TqxWvHW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/22uk7uumo6vwapgpokpq.png" alt="Yosemite sub-areas HTML"&gt;&lt;/a&gt;&lt;br&gt;
To select that with CSS selectors, I selected all the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; tags within &lt;code&gt;div&lt;/code&gt;s of that class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;areas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'div.lef-nav-row a'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If that node set was not empty, I access the &lt;code&gt;href&lt;/code&gt; attribute and use Regex matching to pull out the area ID:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;area_ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;areas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'href'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/[0-9]+/&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If the &lt;code&gt;areas&lt;/code&gt; node set was empty, I look for route information instead. On an area page that contains routes, route IDs are found in a table with an ID of &lt;code&gt;left-nav-route-table&lt;/code&gt;:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Voc-QOSY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cbe3ov2cqfr89nj64i5v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Voc-QOSY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cbe3ov2cqfr89nj64i5v.png" alt="Yosemite sub-area with routes and corresponding HTML"&gt;&lt;/a&gt;&lt;br&gt;
and the code to access the routes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'table#left-nav-route-table a'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Accessing the route ID is similar to accessing area ID:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;route_ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'href'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/[0-9]+/&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;and with route IDs in hand I create Climb entries and use the IDs later to hit Mountain Project's API and flesh out the route information.&lt;/p&gt;

&lt;p&gt;Here's the full code for my scraping method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;getIds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;areaId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parentId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;base_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'https://www.mountainproject.com/area/'&lt;/span&gt;
  &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base_url&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;areaId&lt;/span&gt;
  &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Nokogiri&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="c1"&gt;#get area name and save a new area&lt;/span&gt;
  &lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'h1'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;children&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'in area:'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;current_area&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Area&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;parent_id: 
    &lt;/span&gt;&lt;span class="n"&gt;parentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;mtnproj_id: &lt;/span&gt;&lt;span class="n"&gt;areaId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;#check for subareas&lt;/span&gt;
  &lt;span class="n"&gt;areas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'div.lef-nav-row a'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;areas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;empty?&lt;/span&gt;
    &lt;span class="c1"&gt;#get routes from this area&lt;/span&gt;
    &lt;span class="n"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'table#left-nav-route-table a'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;route_ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; 
       &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'href'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/[0-9]+/&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;route_ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;route_id&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;Climb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;mtnproj_id: 
       &lt;/span&gt;&lt;span class="n"&gt;route_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;area_id: &lt;/span&gt;&lt;span class="n"&gt;current_area&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;area_ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;areas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'href'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/[0- 
       9]+/&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;area_ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;getIds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current_area&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;puts&lt;/code&gt; statement is a visual indicator that my code is progressing through areas as expected, and lets me know which area to start from if my code gets hung up, which did happen a couple times. I tested my method on small areas first with few subareas and routes, and after verifying that it worked as expected, ran it on larger parent areas, ultimately scraping all 222,195 route IDs from Mountain Project. After that it was simple to access Mountain Project's API for the rest of the route information I wanted.&lt;/p&gt;

&lt;p&gt;Going forward I would like to create a background process that updates my route information on a weekly basis so that climbs added to Mountain Project are updated in my database as well. However, the scraping code took days to run through all of Mountain Project's pages, so I'd like to write a more efficient solution for updates.&lt;/p&gt;

&lt;p&gt;Next week I'll walk through how I made my database searchable from the front end and the challenges I encountered in making a user-friendly entry form. For now you can check out &lt;a href="https://rockonapp.com"&gt;RockOn&lt;/a&gt; or watch my &lt;a href="https://youtu.be/WjnEPfqLNiI"&gt;demo video&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>React Context</title>
      <dc:creator>dianakw8591</dc:creator>
      <pubDate>Fri, 10 Apr 2020 01:03:53 +0000</pubDate>
      <link>https://dev.to/dianakw8591/react-context-ijd</link>
      <guid>https://dev.to/dianakw8591/react-context-ijd</guid>
      <description>&lt;p&gt;I'm almost two weeks into learning React, and while working on a &lt;a href="https://www.youtube.com/watch?v=GhCazAgsJzw&amp;amp;feature=youtu.be"&gt;lab that models Westworld's command center&lt;/a&gt; I realized that I was passing props down five levels deep! This process of &lt;em&gt;prop drilling&lt;/em&gt; (vocab word of the day) struck me as a lot of extra typing, and therefore not terribly React-like. For example, information about my hosts was stored in state the top level in App, and passed down into my next components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;//In App&lt;/span&gt;
&lt;span class="nx"&gt;render&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="nc"&gt;Segment&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'app'&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;Headquarters&lt;/span&gt; &lt;span class="na"&gt;hosts&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hosts&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="err"&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="nc"&gt;Segment&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;where it was passed deeper...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in Headquarters&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ColdStorage&lt;/span&gt; &lt;span class="na"&gt;hosts&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;hostsInStorage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;and deeper...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in ColdStorage&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;HostList&lt;/span&gt; &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&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;hosts&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;still deeper...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in HostList&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="nx"&gt;hosts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt; &lt;span class="o"&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Host&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="err"&gt;...&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;and finally down in the Host component the information is actually used.&lt;/p&gt;

&lt;p&gt;That's a lot of repetitive typing for every prop I might need to send from App down to a Host. While there are multiple solutions to this problem, React Context offers one. Straight from the &lt;a href="https://reactjs.org/docs/context.html"&gt;React docs:&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Context provides a way to pass data through the component tree without having to pass props down manually at every level.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Stated this way, Context offers a solution to the exact problem I encountered. So, onto adding Context.&lt;/p&gt;

&lt;p&gt;In my Westworld lab, I want to create a Context that contains my Host data and makes it available to all of the children. The easiest way for me to do this with my current code is to create a new Context in App;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hostContext&lt;/span&gt; &lt;span class="o"&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;createContext&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;host&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;I'm initially creating a Context with a default value of &lt;code&gt;{host: []}&lt;/code&gt; because my host data is fetched asynchronously in &lt;code&gt;componentDidMount&lt;/code&gt; in App. To make this Context available to all of App's children, I'll use React's Provider component, a property of the Context. I'll wrap all of App's children in &lt;code&gt;&amp;lt;hostContext.Provider value={importantDataHere}&amp;gt;&lt;/code&gt; tags. &lt;br&gt;
The &lt;code&gt;value&lt;/code&gt; prop is what contains the information that I want passed down to all of my children components. In this case, I can assign &lt;code&gt;value={hosts: this.state.hosts}&lt;/code&gt; where &lt;code&gt;this.state.hosts&lt;/code&gt; now contains all of my fetched data. To recap, my App component will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hostContext&lt;/span&gt; &lt;span class="o"&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;createContext&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;host&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="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Component&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;hosts&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;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HOSTS_URL&lt;/span&gt;&lt;span class="p"&gt;)&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;resp&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&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;data&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="na"&gt;hosts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;
    &lt;span class="p"&gt;}))&lt;/span&gt;

  &lt;span class="nx"&gt;render&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;hostContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;hosts&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="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Segment&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'app'&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;Headquarters&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;Segment&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;hostContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&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;p&gt;This is great! But how do the children of App (and my new hostContext) access the value passed by the Provider? For class based components, the &lt;code&gt;contextType&lt;/code&gt; property can be assigned to the given Context, and the value accessed using &lt;code&gt;this.context&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Headquarters&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Component&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;hosts&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hosts&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;Headquarters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contextType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hostContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note that only one Context can be assigned to a class based component in this way. &lt;/p&gt;

&lt;p&gt;For functional components, the hook &lt;code&gt;useContext&lt;/code&gt; gives access in the same way that &lt;code&gt;this.context&lt;/code&gt; does for class components, and no need to include any assignment of &lt;code&gt;contextType&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hosts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hostContext&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;hosts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There are plenty of pros and cons to Context and it's not the right choice for every situation, but it seems like a great tool to have in the toolbox!&lt;/p&gt;

</description>
      <category>react</category>
    </item>
    <item>
      <title>Asynchronous Javascript: Callbacks and Promises</title>
      <dc:creator>dianakw8591</dc:creator>
      <pubDate>Tue, 24 Mar 2020 22:38:30 +0000</pubDate>
      <link>https://dev.to/dianakw8591/asynchronous-javascript-callbacks-and-promises-1gbo</link>
      <guid>https://dev.to/dianakw8591/asynchronous-javascript-callbacks-and-promises-1gbo</guid>
      <description>&lt;p&gt;As the Javascript module of Flatiron's Software Engineering immersive wraps up, one thing has become quite clear: I really need to understand callbacks and asynchronous functions to understand how to effectively use Javascript. Below, I've laid out my understanding of callbacks and how promises make asynchronous Javascript easier to user and understand. &lt;/p&gt;

&lt;p&gt;First, we have to understand that Javascript is a synchronous, blocked language where functions only execute after the previous function has finished. But there are also functions available that are asynchronous, &lt;code&gt;fetch&lt;/code&gt; and event handlers for example. Other code will continue to execute while the asynchronous function is waiting to complete, perhaps waiting for response from a server. &lt;/p&gt;

&lt;p&gt;Callbacks can be used in both synchronous and asynchronous Javascript, but often are used in asynchronous ways. Callbacks are functions passed to another function that are called after that function completes. An example of a synchronous callback could be this simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;funcA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;funcB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;funcB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;funcA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;//10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It's just passing a function to another function, in this case, &lt;code&gt;funcA&lt;/code&gt; to &lt;code&gt;funcB&lt;/code&gt;. But that's not very interesting.&lt;/p&gt;

&lt;p&gt;Callbacks used in asynchronous code result in something called "callback hell" which I recommend googling. Basically, something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;asyncAction1&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;asyncAction2&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;asyncAction3&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="c1"&gt;// do something&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It's messy to look at unpleasant to deal with. Promises help to fix this mess by returning a &lt;code&gt;Promise&lt;/code&gt; object that is a proxy for an actual value. It's the promise to return that value, and is either pending, fulfilled, or rejected. &lt;code&gt;.then&lt;/code&gt; can be called on promise and whatever work is done in the &lt;code&gt;.then&lt;/code&gt; block will only be run after the promise has been resolved. Similarly, &lt;code&gt;.catch&lt;/code&gt; will handle errors if the promise is rejected. &lt;/p&gt;

&lt;p&gt;So to rewrite the code above with promises:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;asyncAction1&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;res1&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;asyncAction2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res1&lt;/span&gt;&lt;span class="p"&gt;))&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;res2&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;asyncAction3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res2&lt;/span&gt;&lt;span class="p"&gt;))&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;res3&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;functionThatDoesSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I hear async/await is even cleaner and nicer to use for a variety of reasons, but that part is for another post! Thanks for reading!&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>form_with without JS</title>
      <dc:creator>dianakw8591</dc:creator>
      <pubDate>Tue, 10 Mar 2020 20:15:33 +0000</pubDate>
      <link>https://dev.to/dianakw8591/formwith-without-js-2elo</link>
      <guid>https://dev.to/dianakw8591/formwith-without-js-2elo</guid>
      <description>&lt;p&gt;Last week I was working on a web app to link condition reports and photos with snowpack data from the date and location of the report. The app was built entirely with Ruby on Rails, and I ran into a bug when I tried to use a search form built with &lt;code&gt;form_with&lt;/code&gt;.  The generic search form solution from &lt;a href="https://guides.rubyonrails.org/form_helpers.html"&gt;RailsGuides&lt;/a&gt; seemed like it should work great. Working from the generic form, I got to this point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;%= form_with(url: "/search", method: "get") do %&amp;gt;
    &amp;lt;%= label_tag("Choose locations:") %&amp;gt;
    &amp;lt;%= collection_select(:location, :id, Location.all, :id, :name) %&amp;gt;&amp;lt;br&amp;gt;
    &amp;lt;%= label_tag(:min, "Minimum Snow Depth (in):") %&amp;gt;
    &amp;lt;%= number_field_tag(:min) %&amp;gt;&amp;lt;br&amp;gt;
    &amp;lt;%= label_tag(:max, "Maximum Snow Depth (in):") %&amp;gt;
    &amp;lt;%= number_field_tag(:max) %&amp;gt;&amp;lt;br&amp;gt;
    &amp;lt;%= submit_tag("Search Posts") %&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Having used &lt;code&gt;form_for&lt;/code&gt; and &lt;code&gt;form_tag&lt;/code&gt; in the past, the syntax looked familiar, but when I submitted a search, nothing happened! I knew I was hitting the right route and my log even said that it was rendering the results page. But no new page was rendered.&lt;/p&gt;

&lt;p&gt;Enter the &lt;code&gt;:local&lt;/code&gt; option. By default, &lt;code&gt;form_with&lt;/code&gt; submits are XMLHttpRequest (XHR) objects - put another way, they are AJAX requests. The main benefit of AJAX (Asynchronous JavaScript And XML) is that it communicates with the server and renders new data without a full page refresh. The first line of html generated from my original &lt;code&gt;form_with&lt;/code&gt; with default options looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;accept-charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/search"&lt;/span&gt; &lt;span class="na"&gt;data-remote=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"get"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;data-remote="true"&lt;/code&gt; bit tells Rails to submit the data as an AJAX request. But without Javascript in the mix, this default option was causing problems.&lt;/p&gt;

&lt;p&gt;In order to disable the default remote submits, add &lt;code&gt;local: true&lt;/code&gt; as an option to the form, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;%= form_with(url: "/search", method: "get", local: true) do %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After that, my results page rendered as expected. &lt;/p&gt;

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