<?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: Lyndsi Kay Williams</title>
    <description>The latest articles on DEV Community by Lyndsi Kay Williams (@lyndsiwilliams).</description>
    <link>https://dev.to/lyndsiwilliams</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%2F557498%2F9dacf185-7d72-41e2-bfcb-9993e1bace89.jpg</url>
      <title>DEV Community: Lyndsi Kay Williams</title>
      <link>https://dev.to/lyndsiwilliams</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lyndsiwilliams"/>
    <language>en</language>
    <item>
      <title>Apache Superset: Installing locally is easy using the makefile</title>
      <dc:creator>Lyndsi Kay Williams</dc:creator>
      <pubDate>Sun, 20 Aug 2023 18:01:01 +0000</pubDate>
      <link>https://dev.to/lyndsiwilliams/apache-superset-installing-locally-is-easy-using-the-makefile-4ofi</link>
      <guid>https://dev.to/lyndsiwilliams/apache-superset-installing-locally-is-easy-using-the-makefile-4ofi</guid>
      <description>&lt;p&gt;Are you interested in trying out Superset, but you're intimidated by the local setup process? Worry not! Superset needs some initial setup to install locally, but I've got a streamlined way to get started - using &lt;a href="https://github.com/apache/superset/blob/master/Makefile" rel="noopener noreferrer"&gt;the makefile&lt;/a&gt;! This file contains a set of scripts to simplify the setup process.&lt;/p&gt;

&lt;p&gt;This setup is for Mac OS X, for other OS setups see: &lt;a href="https://superset.apache.org/docs/installation/installing-superset-from-scratch/" rel="noopener noreferrer"&gt;https://superset.apache.org/docs/installation/installing-superset-from-scratch/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To start, fork and download Superset from Github: &lt;a href="https://github.com/apache/superset" rel="noopener noreferrer"&gt;https://github.com/apache/superset&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can run Superset directly without forking it, but you won't be able to create pull requests unless you're using your own forked version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Superset has some prerequisites in order to run properly. Let's start with dependencies:&lt;/p&gt;

&lt;p&gt;Make sure to update your machine to the latest version of Mac OS X. After updating, install the latest version of XCode command line tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xcode-select --install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Going forward, we'll be using &lt;strong&gt;Homebrew&lt;/strong&gt; to install dependencies: &lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;https://brew.sh/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Node&lt;/strong&gt;: Currently, Superset works best with &lt;code&gt;Node.js&lt;/code&gt; version 16 and &lt;code&gt;npm&lt;/code&gt; version 7. If you've got a preferred version of node, I suggest &lt;a href="https://github.com/nvm-sh/nvm#usage" rel="noopener noreferrer"&gt;using Node Version Manager (NVM)&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/nvm-sh/nvm#install--update-script" rel="noopener noreferrer"&gt;See here for full NVM installation instructions&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nvm install 16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Python&lt;/strong&gt;: Currently, Superset works best with Python version 3.9. We'll be using a Python virtual environment, so for now just install the Python version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install python@3.9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to update &lt;code&gt;pip&lt;/code&gt; and &lt;code&gt;setuptools&lt;/code&gt; as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install --upgrade setuptools pip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Almost done, now we need the rest of the dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install readline pkg-config libffi openssl mysql postgresql@14
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set LDFLAGS and CFLAGS to allow certain Python packages to build properly. You can export the variables with these commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export LDFLAGS="-L$(brew --prefix openssl)/lib"
export CFLAGS="-I$(brew --prefix openssl)/include"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will need to set a secret key in your &lt;code&gt;superset_config.py&lt;/code&gt; file for security reasons. Open superset in your favorite code editor and create a file called &lt;code&gt;superset_config.py&lt;/code&gt; in the root folder. In this file, set your secret key like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SECRET_KEY='insertSecurePasswordHere'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Python Virtual Environment
&lt;/h2&gt;

&lt;p&gt;Now we can set up our Python virtual environment. Start by installing &lt;code&gt;virtualenv&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install virtualenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;cd&lt;/code&gt; into wherever you've locally cloned your forked instance of Superset. Create a virtual environment with Python 3.9:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Create a venv directory
python3.9 -m venv venv

// Open the virtual environment
. venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will need two terminal windows to run Superset, I like to use iTerm2's horizontal window stacking to keep my terminal windows together: &lt;a href="https://iterm2.com/" rel="noopener noreferrer"&gt;https://iterm2.com/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Now it's time for the Makefile magic ✨
&lt;/h2&gt;

&lt;p&gt;Make sure you're at the root file of Superset and in a virtual environment. Run this command to install Superset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;make install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it, you're installing Superset! This script will run for a bit, bring a snack.&lt;/p&gt;

&lt;p&gt;Once the installation is complete, it's time to get things running. Boot up the back end with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;make flask-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a separate terminal window, once again make sure you're at the root file of Superset and in a virtual environment. Boot up the front end with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;make node-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once webpack finishes loading the app, go to &lt;code&gt;localhost:9000&lt;/code&gt; in your browser. You'll see a login screen, log in with these credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Username: admin
Password: general
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You're in! Welcome to Superset, enjoy your experience and feel free to contribute. &lt;a href="https://github.com/apache/superset/blob/master/CONTRIBUTING.md" rel="noopener noreferrer"&gt;It's open source&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>react</category>
      <category>python</category>
    </item>
    <item>
      <title>Real DOM, Virtual DOM, Shadow DOM, What's the Difference?</title>
      <dc:creator>Lyndsi Kay Williams</dc:creator>
      <pubDate>Sun, 16 Jul 2023 14:40:20 +0000</pubDate>
      <link>https://dev.to/lyndsiwilliams/real-dom-virtual-dom-shadow-dom-whats-the-difference-32ni</link>
      <guid>https://dev.to/lyndsiwilliams/real-dom-virtual-dom-shadow-dom-whats-the-difference-32ni</guid>
      <description>&lt;p&gt;Real DOMs and virtual DOMs and shadow DOMs, oh my! Let's take a dive to see how they all work together to create a clean, performant Document Object Model.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;DOM (Document Object Model)&lt;/strong&gt; is exactly as it states. The HTML tree of a website is represented by an object called &lt;code&gt;document&lt;/code&gt;. In this object there is a model of the HTML tree's elements, conveniently accessible by &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors" rel="noopener noreferrer"&gt;object dot notation&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;document.head&lt;/code&gt; will return the &lt;code&gt;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&lt;/code&gt; section of the tree, &lt;code&gt;document.body&lt;/code&gt; will return the &lt;code&gt;&amp;lt;body&amp;gt;&amp;lt;/body&amp;gt;&lt;/code&gt; section of the tree, and so on.
You can also use this dot notation to manipulate the DOM. For example: &lt;code&gt;document.body.style.background = ‘red’&lt;/code&gt; will change the body’s background color to red. You can see more about the DOM API in &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Document" rel="noopener noreferrer"&gt;Mozilla's web docs&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This DOM is referred to as the page's &lt;strong&gt;real DOM&lt;/strong&gt;. The real DOM, by itself, is only able to update the entire DOM simultaneously every time there is a change to the DOM. This makes it very slow and expensive to make updates to the page. That's where the virtual DOM comes to save the day!&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;virtual DOM&lt;/strong&gt; is a virtual representation of the real DOM. This virtual DOM is kept in memory and synced with the real DOM. React compiles the real DOM into Javascript, which is the first step in creating more performant updates. The virtual DOM then makes a copy of itself (let's call it virtual DOM 2). When an update is made on the page, it is first applied to virtual DOM 2. React then compares virtual DOM 2 to the original virtual DOM, an exact copy of the real DOM. React uses this comparison to quickly detect where the real DOM needs to be updated and updates &lt;em&gt;only those elements&lt;/em&gt; instead of the entire DOM. This is where the magic happens, it is much quicker and less expensive to update only what needs to be updated.&lt;/p&gt;

&lt;p&gt;If you want to see the virtual DOM in action, you can see a visual representation with the "Paint flashing" feature in Google Chrome's inspect tool:&lt;/p&gt;

&lt;p&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%2Fuploads%2Farticles%2Fohmjr3t05tn87hm0ecch.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%2Fuploads%2Farticles%2Fohmjr3t05tn87hm0ecch.png" alt="screenshot of the Paint flashing feature in Google Chrome's inspect tool"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check that box and then play with the page, any DOM changes will be highlighted with a green box.&lt;/p&gt;

&lt;p&gt;Last but not least, we have the elusive &lt;strong&gt;shadow DOM&lt;/strong&gt;. This allows hidden DOM trees to be attached to elements in the regular DOM tree. Custom elements can be created with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements" rel="noopener noreferrer"&gt;the Web API&lt;/a&gt;, these are controlled solely by the shadow DOM. It's important to remember that the real DOM and the shadow DOM are completely different realms. Changes made to elements in the real DOM will not apply to elements in the shadow DOM, and vice versa.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you're sleuthing through HTML elements in the inspect tool and don't see something listed when you're looking right at it on the page, it's probably in the shadow DOM. The best example is video players. Visually on the page you can see the internal UI: the play button, skip button, share button, etc. but you don't see it in the real DOM. It's being controlled by the shadow DOM.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&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%2Fuploads%2Farticles%2F3yp196vh8rxugfr79bf7.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%2Fuploads%2Farticles%2F3yp196vh8rxugfr79bf7.png" alt="Three panel Simba meme. First panel text: "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Elusive as it may be, you can actually reveal the shadow DOM if you need it! In Google Chrome's inspect tool: Go to the settings, select Preferences and go to the Elements section. Select "Show user agent shadow DOM" to show any shadow DOMs alongside the real DOM in the Elements tab of the inspect tool.&lt;/p&gt;

&lt;p&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%2Fuploads%2Farticles%2Fne9xa86wpco5ygi8cipd.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%2Fuploads%2Farticles%2Fne9xa86wpco5ygi8cipd.png" alt="screenshot of the Show user agent shadow DOM option"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's all three! Hopefully this blog has brought you a better understanding of the differences among the real DOM, the virtual DOM, and the shadow DOM. Let me know what you think in the comments!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>frontend</category>
      <category>performance</category>
    </item>
    <item>
      <title>React hooks: An advanced look at converting useState to useReducer</title>
      <dc:creator>Lyndsi Kay Williams</dc:creator>
      <pubDate>Wed, 10 May 2023 15:45:09 +0000</pubDate>
      <link>https://dev.to/lyndsiwilliams/react-hooks-an-advanced-look-at-converting-usestate-to-usereducer-2il6</link>
      <guid>https://dev.to/lyndsiwilliams/react-hooks-an-advanced-look-at-converting-usestate-to-usereducer-2il6</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/lyndsiwilliams/react-hooks-how-to-convert-usestate-to-usereducer-5f64"&gt;my previous blog&lt;/a&gt;, I gave a basic demonstration on how to manage state with &lt;code&gt;useReducer&lt;/code&gt; instead of &lt;code&gt;useState&lt;/code&gt;. In this blog, I'll dive into a more complex example.&lt;/p&gt;

&lt;p&gt;When managing state for a form, things can get complex quickly. Take this form, for example:&lt;/p&gt;

&lt;p&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%2Fuploads%2Farticles%2Fkligigf7cy67h2p5rwu5.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%2Fuploads%2Farticles%2Fkligigf7cy67h2p5rwu5.png" alt="basic form"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To manage the form's state locally with &lt;code&gt;useState&lt;/code&gt;, it would look something like this:&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="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;setName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTitle&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;favoriteNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFavoriteNumber&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;favoriteColor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFavoriteColor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This might seem manageable enough for now - but if the form needs to grow, one &lt;code&gt;useState&lt;/code&gt; per input will turn your code into spaghetti before you know it!  Let's take a look at how we can make state management more scaleable with &lt;code&gt;useReducer&lt;/code&gt; using the same steps shown in my previous blog:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Define an initial state and an action type.&lt;/li&gt;
&lt;li&gt;Replace the &lt;code&gt;useState&lt;/code&gt; hook with the &lt;code&gt;useReducer&lt;/code&gt; hook.&lt;/li&gt;
&lt;li&gt;Create a reducer function that takes a state and an action and returns a new state.&lt;/li&gt;
&lt;li&gt;Update the component to use the new state and dispatch functions returned by the &lt;code&gt;useReducer&lt;/code&gt; hook, which should have the reducer and initial state passed in.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Following the steps above, we can convert our &lt;code&gt;useState&lt;/code&gt; state to &lt;code&gt;useReducer&lt;/code&gt; state.&lt;/p&gt;

&lt;h5&gt;
  
  
  1. Define an initial state and an action type:
&lt;/h5&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;initialState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Default name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Default title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;favorite_number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;favorite_primary_color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;INPUT_CHANGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;inputChange&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;h5&gt;
  
  
  2. Replace the &lt;code&gt;useState&lt;/code&gt; hook with the &lt;code&gt;useReducer&lt;/code&gt; hook:
&lt;/h5&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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;useReducer&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;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FormComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFormData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useReducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formReducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;
&lt;h5&gt;
  
  
  3. Create a reducer function that takes a state and an action and returns a new state:
&lt;/h5&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;formReducer&lt;/span&gt; &lt;span class="o"&gt;=&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;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stateCopy&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="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="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;INPUT_CHANGE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;stateCopy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&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;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&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="nl"&gt;default&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;null&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;h5&gt;
  
  
  4. Update the component to use the new state and dispatch functions returned by the &lt;code&gt;useReducer&lt;/code&gt; hook, which should have the reducer and initial state passed in:
&lt;/h5&gt;
&lt;div class="highlight js-code-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;FormComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFormData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useReducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formReducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialState&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;internalOnchange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&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="nf"&gt;setFormData&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="c1"&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;form&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;input&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;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"name"&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;"name"&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="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;internalOnchange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;INPUT_CHANGE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;name&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="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="na"&gt;value&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="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="p"&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;gt;&lt;/span&gt;

    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&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;form&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;Step 4 is a little more complex in this example. In order to pass the type and payload to the reducer cleanly, I've implemented an &lt;code&gt;internalOnchange&lt;/code&gt; helper function. Now the &lt;code&gt;internalOnchange&lt;/code&gt; can be passed into any input on the form, as shown on the name input above.&lt;/p&gt;

&lt;p&gt;As long as the name attribute of the input matches the data you want to change, that value in state will be changed. Now the form can have unlimited inputs with no need to change the state management functionality!&lt;/p&gt;

&lt;p&gt;...unless the form gets &lt;em&gt;even more&lt;/em&gt; complex?? Not a problem, you can add another action to your &lt;code&gt;formReducer&lt;/code&gt; to manage any specialized inputs. To see this form as a completed project, &lt;a href="https://github.com/lyndsiWilliams/vite-example" rel="noopener noreferrer"&gt;check it out here on Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I've created the example form explained above - it changes state independently by action, but I've also included an option to change the data as a whole by manipulating the entire JSON directly. This is done by &lt;a href="https://github.com/lyndsiWilliams/vite-example/blob/main/client/src/components/EditWithJSON.tsx#L21C10-L24" rel="noopener noreferrer"&gt;passing the entire changed JSON as the payload here&lt;/a&gt; and &lt;a href="https://github.com/lyndsiWilliams/vite-example/blob/main/client/src/state/formReducer.ts#L16-L20" rel="noopener noreferrer"&gt;using an &lt;code&gt;updateData&lt;/code&gt; action, created here&lt;/a&gt;. This project will look a little different than the blog example since it's done in TypeScript, I wanted to keep things simple in this blog so I explained it in JavaScript.&lt;/p&gt;

&lt;p&gt;I hope this blog clearly explained using &lt;code&gt;useReducer&lt;/code&gt; to handle state instead of &lt;code&gt;useState&lt;/code&gt;. If you have any questions or comments, I'd love to hear what you've got!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>React hooks: How to convert useState to useReducer</title>
      <dc:creator>Lyndsi Kay Williams</dc:creator>
      <pubDate>Wed, 22 Feb 2023 01:43:03 +0000</pubDate>
      <link>https://dev.to/lyndsiwilliams/react-hooks-how-to-convert-usestate-to-usereducer-5f64</link>
      <guid>https://dev.to/lyndsiwilliams/react-hooks-how-to-convert-usestate-to-usereducer-5f64</guid>
      <description>&lt;p&gt;&lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useReducer&lt;/code&gt; are both React hooks that allow you to manage state in your components. &lt;code&gt;useState&lt;/code&gt; is a simpler hook that allows you to manage a single piece of state, while &lt;code&gt;useReducer&lt;/code&gt; is more powerful and allows you to manage more complex state that may have multiple values and require more sophisticated updates.&lt;/p&gt;

&lt;p&gt;To convert from &lt;code&gt;useState&lt;/code&gt; to &lt;code&gt;useReducer&lt;/code&gt;, you can follow these general steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Define an initial state and an action type.&lt;/li&gt;
&lt;li&gt;Replace the &lt;code&gt;useState&lt;/code&gt; hook with the &lt;code&gt;useReducer&lt;/code&gt; hook.&lt;/li&gt;
&lt;li&gt;Create a reducer function that takes a state and an action and returns a new state.&lt;/li&gt;
&lt;li&gt;Update the component to use the new state and dispatch functions returned by the &lt;code&gt;useReducer&lt;/code&gt; hook, which should have the reducer and initial state passed in.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is a basic example of how to convert a component that uses &lt;code&gt;useState&lt;/code&gt; to manage a single piece of state. Start with a Counter component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;increment&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="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Count: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&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;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Increment&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;To convert this to use &lt;code&gt;useReducer&lt;/code&gt;, we can follow the steps outlined above:&lt;/p&gt;

&lt;h5&gt;
  
  
  1. Define an initial state and an action type:
&lt;/h5&gt;



&lt;div class="highlight js-code-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;initialState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;count&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;INCREMENT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;increment&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;h5&gt;
  
  
  2. Replace the &lt;code&gt;useState&lt;/code&gt; hook with a &lt;code&gt;useReducer&lt;/code&gt; hook:
&lt;/h5&gt;



&lt;div class="highlight js-code-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;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useReducer&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;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useReducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  3. Create a reducer function that takes a state and an action and returns a new state:
&lt;/h5&gt;



&lt;div class="highlight js-code-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;reducer&lt;/span&gt; &lt;span class="o"&gt;=&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;action&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;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;INCREMENT&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="na"&gt;count&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;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&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;h5&gt;
  
  
  4. Update the component to use the new state and dispatch functions returned by the &lt;code&gt;useReducer&lt;/code&gt; hook, which should have the reducer and initial state passed in:
&lt;/h5&gt;



&lt;div class="highlight js-code-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;Counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useReducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialState&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;increment&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="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;INCREMENT&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Count: &lt;span class="si"&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;count&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;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Increment&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&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;In step 4, the dispatch function is used to send an action to the reducer function. The reducer function then returns a new state based on the action type. The component is also updated to use &lt;code&gt;state.count&lt;/code&gt; instead of the &lt;code&gt;count&lt;/code&gt; variable previously returned by &lt;code&gt;useState&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this simple example, &lt;code&gt;useReducer&lt;/code&gt; doesn't bring many benefits over &lt;code&gt;useState&lt;/code&gt;. But in general, as your components grow in complexity, &lt;code&gt;useReducer&lt;/code&gt; provides a more powerful and flexible way to manage state - especially when you have more complex state that require multiple values and more sophisticated updates.&lt;/p&gt;

</description>
      <category>codenewbie</category>
      <category>career</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Apache Superset: Testing and Enzyme to RTL conversion</title>
      <dc:creator>Lyndsi Kay Williams</dc:creator>
      <pubDate>Tue, 31 May 2022 17:56:53 +0000</pubDate>
      <link>https://dev.to/lyndsiwilliams/superset-testing-and-enzyme-to-rtl-conversion-1j6a</link>
      <guid>https://dev.to/lyndsiwilliams/superset-testing-and-enzyme-to-rtl-conversion-1j6a</guid>
      <description>&lt;p&gt;Superset uses &lt;a href="https://jestjs.io/" rel="noopener noreferrer"&gt;Jest&lt;/a&gt; and &lt;a href="https://testing-library.com/docs/react-testing-library/intro/" rel="noopener noreferrer"&gt;React Testing Library (RTL)&lt;/a&gt; to write unit and integration tests. In the past we used &lt;a href="https://enzymejs.github.io/enzyme/" rel="noopener noreferrer"&gt;Enzyme&lt;/a&gt;, but now that we're currently converting all of our class components to functional components, Enzyme cannot support our testing needs. Since RTL is better for testing functional components, we're converting all of our test files to RTL. This can be quite a learning curve - I've gone through a lot of the process so I'd like to share what I've learned so far.&lt;/p&gt;

&lt;p&gt;First and foremost: We have a &lt;a href="https://github.com/apache/superset/wiki/Testing-Guidelines-and-Best-Practices" rel="noopener noreferrer"&gt;Testing Guidelines and Best Practices&lt;/a&gt; document that outlines all the code styles we adhere to in our tests. Please use this document as reference when writing your tests.&lt;/p&gt;

&lt;p&gt;The main thing you want to keep in mind is the different approach each testing library uses in testing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enzyme is code-focused testing. It tests things in the "back" of the code that the user never sees, such as the props of a component.&lt;/li&gt;
&lt;li&gt;RTL is user-focused testing. All of your tests will rely on things the user can see and do.

&lt;ul&gt;
&lt;li&gt;For example: If there were an Enzyme test that checks the props of a component, you would look for where those props show visually on the component and capture it with RTL.&lt;/li&gt;
&lt;li&gt;Except for certain things like API mocking, Superset uses fetch-mock for that. &lt;a href="http://www.wheresrhys.co.uk/fetch-mock/" rel="noopener noreferrer"&gt;Here's a link to the docs&lt;/a&gt;, if you'd like to learn more about how to mock API calls in RTL. You can also look for other already-existing instances of fetch-mock in the codebase to see how it's used in Superset.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The test environment in Superset is getting healthier and easier to work with by the day, and I hope this will inspire you to help contribute to the cause! To wrap this up, I would like to leave you with some good RTL/testing resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In your tests, use these commands to help with debugging:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;screen.debug()&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;This will show you the rendered component in the console when you run the test. You can pass in a captured element if you want to see just that element instead of the whole rendered component.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;screen.logTestingPlaygroundURL()&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;This will give you a link in the console when you run your test. Click this link and it will open an instance of the testing playground displaying your rendered component (or a captured element passed into the function) in the browser. &lt;a href="https://testing-playground.com/" rel="noopener noreferrer"&gt;Check out this link&lt;/a&gt; for an example of what that looks like, this is a really cool feature 😁 It would look like this in the code:
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logTestingPlaygroundURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;I converted 11 files in &lt;a href="https://github.com/apache/superset/pull/16626" rel="noopener noreferrer"&gt;this pull request&lt;/a&gt;, feel free to use it as a reference for conversions&lt;/li&gt;
&lt;li&gt;The RTL docs have a good &lt;a href="https://testing-library.com/docs/react-testing-library/migrate-from-enzyme/" rel="noopener noreferrer"&gt;guide for converting from Enzyme&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://testing-library.com/docs/react-testing-library/cheatsheet" rel="noopener noreferrer"&gt;RTL cheatsheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jestjs.io/docs/expect" rel="noopener noreferrer"&gt;Jest matchers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/testing-library/jest-dom" rel="noopener noreferrer"&gt;jest-dom matchers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Superset has a very handy &lt;a href="https://github.com/apache/superset/blob/master/superset-frontend/spec/helpers/testing-library.tsx" rel="noopener noreferrer"&gt;helper file&lt;/a&gt; for RTL with supercharged functionality for our specific needs.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>testing</category>
      <category>react</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
