<?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: Richard Ng</title>
    <description>The latest articles on DEV Community by Richard Ng (@richardcrng).</description>
    <link>https://dev.to/richardcrng</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%2F281659%2Fe9717274-8499-44b8-a0af-e502ac411d6b.jpeg</url>
      <title>DEV Community: Richard Ng</title>
      <link>https://dev.to/richardcrng</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/richardcrng"/>
    <language>en</language>
    <item>
      <title>Why you can stop writing all that Redux boilerplate</title>
      <dc:creator>Richard Ng</dc:creator>
      <pubDate>Mon, 02 Dec 2019 19:54:54 +0000</pubDate>
      <link>https://dev.to/richardcrng/why-you-can-stop-writing-all-that-redux-boilerplate-1fo7</link>
      <guid>https://dev.to/richardcrng/why-you-can-stop-writing-all-that-redux-boilerplate-1fo7</guid>
      <description>&lt;p&gt;&lt;b&gt;Should I read this post?&lt;/b&gt;&lt;br&gt;
I think that you are more likely to find value in reading this post if you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Are interested in trying to cut down your Redux boilerplate; or&lt;/li&gt;
&lt;li&gt;Enjoy it when conventional coding patterns are challenged; or&lt;/li&gt;
&lt;li&gt;Like investigating shiny new libraries for state management!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I have a provocative opinion. I contend that &lt;strong&gt;a lot of your Redux boilerplate can be entirely eliminated&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Not all of it - I've not completely lost my mind. Just &lt;em&gt;a great deal of it&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Here's how I'm going to make my case.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Firstly, I'm going to introduce a fictional project scenario;&lt;/li&gt;
&lt;li&gt;Secondly, I'm going to look at what Redux boilerplate might typically be used;&lt;/li&gt;
&lt;li&gt;Thirdly, I'm going to demonstrate how this boilerplate can be eliminated.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Project Scenario
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Situation: a web development agency and a client
&lt;/h3&gt;

&lt;p&gt;Let's suppose that we have a web development agency, &lt;em&gt;Devs2U&lt;/em&gt;, working on a project with a new client, &lt;em&gt;MegaCorp&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;It's an important project, both for MegaCorp and Devs2U - currently, neither are profitable, but if this project works out then it could turn things around for both of them.&lt;/p&gt;

&lt;p&gt;Given the importance of the project, Devs2U's CTO, Maisy, has staffed herself on the project and is currently planning out who else to staff, and what exactly they'll be doing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// initialState.js&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;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;project&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;agency&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Devs2U&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;revenue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;costs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80000&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;client&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MegaCorp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;revenue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1500000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;costs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;7400000&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;budgeted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;days&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="na"&gt;salaries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;stagesCompleted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;discover&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;design&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;develop&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;test&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;technologies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;languages&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="s1"&gt;javascript&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;libraries&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="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="c1"&gt;// look, ma, no Redux! (... yet)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;persons&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="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;Maisy Ware&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;CTO&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;employedBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;agency&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;determined&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="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;Maddie Swanson&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;CTO&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;employedBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;anxious&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="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;Kian Bernard&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;Junior Developer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;employedBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;agency&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eager&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;h3&gt;
  
  
  Complication: The developer team don't love Redux state management
&lt;/h3&gt;

&lt;p&gt;As she's planning and scoping out the project, Maisy realises that, despite her initial plan to not use Redux, it's going to make the state management significantly easier if she does.&lt;/p&gt;

&lt;p&gt;However, although Maisy loves Redux, some of her team don't - they've complained to her that it can be tedious to set up, difficult to learn and painful to maintain.&lt;/p&gt;

&lt;p&gt;As such, Maisy decides to take responsibility for architecting the project's Redux code in a way that is quick to setup, easy to learn and simple to scale.&lt;/p&gt;

&lt;h3&gt;
  
  
  Question: How can we set up Redux with minimal boilerplate?
&lt;/h3&gt;

&lt;p&gt;Let's model this situation using a Redux store.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// store.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createStore&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;redux&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;initialState&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;./path/to/initialState&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/* our root reducer */&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;store&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="cm"&gt;/* some 'LIBRARY_ADDED'-ish action */&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;technologies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;libraries&lt;/span&gt; &lt;span class="c1"&gt;// desired: ['react', 'redux']&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So, how can we get our root reducer and this action to add Redux to the list of libraries used?&lt;/p&gt;

&lt;h2&gt;
  
  
  Typical approaches
&lt;/h2&gt;

&lt;p&gt;Here, I'll show three approaches that might be used, and discuss and compare them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vanilla&lt;/li&gt;
&lt;li&gt;Immer&lt;/li&gt;
&lt;li&gt;
ReduxToolkit

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;createAction&lt;/code&gt; with &lt;code&gt;createReducer&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;createSlice&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's probably worth noting that in all these cases, it would be more common to break up the root reducer into child reducers and then make a call to Redux's &lt;a href="https://redux.js.org/api/combinereducers"&gt;&lt;code&gt;combineReducers&lt;/code&gt;&lt;/a&gt; - but this is more set up work to do, and we're interested here in handling our &lt;code&gt;'LIBRARY_ADDED'&lt;/code&gt; case as quickly and straightforwardly as possible, so we'll exclude that from our examples.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vanilla
&lt;/h3&gt;

&lt;p&gt;A 'vanilla' approach might look 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="c1"&gt;// actions.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addLibrary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;library&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;LIBRARY_ADDED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;library&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// reducer.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rootReducer&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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;initialState&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;LIBRARY_ADDED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;project&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;technologies&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;technologies&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;libraries&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="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;technologies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;libraries&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="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&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="nx"&gt;state&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// store.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rootReducer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;store&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="nx"&gt;addLibrary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redux&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;technologies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;libraries&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; ['react', 'redux']&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;h3&gt;
  
  
  Immer
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://immerjs.github.io/immer/docs/introduction"&gt;&lt;code&gt;immer&lt;/code&gt;&lt;/a&gt; is a cool library that lets you write immutable updates in a way that &lt;em&gt;feels&lt;/em&gt; mutable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// actions.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addLibrary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;library&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;LIBRARY_ADDED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;library&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// reducer.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;produce&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;immer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rootReducer&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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;initialState&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="nx"&gt;produce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baseState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;draftState&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;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;LIBRARY_ADDED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// not actually mutating state below, but modifying a draft&lt;/span&gt;
      &lt;span class="c1"&gt;// which immer uses to return the new state&lt;/span&gt;
      &lt;span class="nx"&gt;draftState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;technologies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;libraries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&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="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// store.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rootReducer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;store&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="nx"&gt;addLibrary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redux&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;technologies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;libraries&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; ['react', 'redux']&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;h3&gt;
  
  
  Redux Toolkit
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://redux-toolkit.js.org/"&gt;Redux Toolkit&lt;/a&gt; is the new and &lt;em&gt;officially recomended way to write Redux&lt;/em&gt;, a library written by the Redux maintainers.&lt;/p&gt;

&lt;p&gt;Here are two examples of how we might use the library to handle this specific case of adding a library.&lt;/p&gt;

&lt;h4&gt;
  
  
  a) &lt;code&gt;createAction&lt;/code&gt; with &lt;code&gt;createReducer&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// actions.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createAction&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;@reduxjs/toolkit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addLibrary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;LIBRARY_ADDED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// reducer.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createReducer&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;@reduxjs/toolkit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rootReducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createReducer&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="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;addLibrary&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="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="c1"&gt;// action.payload will be the argument passed to addLibrary&lt;/span&gt;
    &lt;span class="c1"&gt;// RTK uses immer under-the-hood for the same mutative 'feel'&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;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;technologies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;libraries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// store.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rootReducer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;store&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="nx"&gt;addLibrary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redux&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;technologies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;libraries&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; ['react', 'redux']&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;h4&gt;
  
  
  b) &lt;code&gt;createSlice&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// reducer.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createSlice&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;@reduxjs/toolkit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createSlice&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;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;reducers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;addLibrary&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="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;technologies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;libraries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&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="p"&gt;}&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;// store.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createStore&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;reducer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;store&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="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addLibrary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redux&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;technologies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;libraries&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; ['react', 'redux']&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;h3&gt;
  
  
  Discussion
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Strong direction of travel
&lt;/h4&gt;

&lt;p&gt;I think there's clearly a good direction of travel throughout these examples. In particular, I know that Mark Erikson (maintainer of Redux) has put a great deal of work into Redux Toolkit, and I think that shows: &lt;code&gt;createSlice&lt;/code&gt; is, imo, a big improvement on having to manually write your action creators and reducer logic separately.&lt;/p&gt;

&lt;h4&gt;
  
  
  All are painful to scale...
&lt;/h4&gt;

&lt;p&gt;I believe that there's a core problem not being addressed, though - &lt;strong&gt;they're all going to be painful to scale&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In the different approaches, handling a single case / action type is being optimised - but as your application grows, you'll still need to handle a whole bunch of different cases.&lt;/p&gt;

&lt;p&gt;This either means that your root reducer grows into a tremendously large beast, or (more likely) you split it up into reducers handling different slices of state, which leads to a great proliferation of files that you need to maintain.&lt;/p&gt;

&lt;p&gt;One of these is certainly the lesser of two evils, but both are additional developer work for you to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Redux-Leaves: write once, reduce anywhere
&lt;/h2&gt;

&lt;p&gt;This is why I wrote &lt;a href="https://redux-leaves.js.org"&gt;Redux-Leaves&lt;/a&gt;: to make Redux quicker to setup and simpler to scale.&lt;/p&gt;

&lt;h3&gt;
  
  
  Boilerplate? What boilerplate?
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// store.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;reduxLeaves&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;redux-leaves&lt;/span&gt;&lt;span class="dl"&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;reducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;reduxLeaves&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;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createStore&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;store&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="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;technologies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;libraries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redux&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;technologies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;libraries&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; ['react', 'redux']&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here's the key difference: unlike the typical approaches, with Redux-Leaves &lt;strong&gt;you're not having to manually set up specific cases for trivial things&lt;/strong&gt; like pushing to an array. Redux-Leaves gives you a bunch of sensible &lt;a href="https://redux-leaves.js.org/docs/defaults/overview"&gt;default action creators out-of-the-box&lt;/a&gt;, that can be &lt;a href="https://redux-leaves.js.org/docs/api/create"&gt;used at an arbitrary leaf of your state tree&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple usage: describe the change you want to see
&lt;/h3&gt;

&lt;p&gt;If you can describe the state change you want to see, you can dispatch the correct action.&lt;/p&gt;

&lt;p&gt;You can play around with these simple examples on &lt;a href="https://runkit.com/richardcrng/no-boilerplate-with-redux-leaves-simple-usage"&gt;RunKit&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Pushing &lt;code&gt;'redux'&lt;/code&gt; to the libraries array
&lt;/h4&gt;

&lt;h5&gt;
  
  
  1. Where do we want state to change?
&lt;/h5&gt;

&lt;p&gt;&lt;code&gt;storeState.project.technologies.libraries&lt;/code&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  2. What change do we want to see?
&lt;/h5&gt;

&lt;p&gt;We want to push the string &lt;code&gt;'redux'&lt;/code&gt; into the array&lt;/p&gt;

&lt;h5&gt;
  
  
  3. What action should I create for dispatching?
&lt;/h5&gt;

&lt;p&gt;&lt;code&gt;actions.project.technologies.libraries.create.push('redux')&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;actions.projects.technologies.libraries&lt;/code&gt; accesses the relevant path&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.create&lt;/code&gt; opens up action creators at that particular path&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.push('redux')&lt;/code&gt; means we create a 'push' action for the payload &lt;code&gt;'redux'&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Budgeting more days and salaries
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// At storeState.project.budgeted.days, I want to create an increment action&lt;/span&gt;
&lt;span class="nx"&gt;store&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="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;budgeted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;days&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&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="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;budgeted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;days&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 3&lt;/span&gt;

&lt;span class="c1"&gt;// Similar for storeState.project.budgeted.salaries, but I want to increment by 5000&lt;/span&gt;
&lt;span class="nx"&gt;store&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="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;budgeted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;salaries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&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="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;budgeted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;salaries&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 15000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;h4&gt;
  
  
  Updating inside an array
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// At storeState.persons, I want to update the status property of the 1st element to excited&lt;/span&gt;
&lt;span class="nx"&gt;store&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="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;persons&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="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;excited&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;persons&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="cm"&gt;/*
  {
    name: 'Maddie Swanson',
    title: 'CTO',
    employedBy: 'client',
    status: 'excited'
  }
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  Do a bunch of things together
&lt;/h4&gt;



&lt;div class="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;bundle&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;reduxLeaves&lt;/span&gt;

&lt;span class="nx"&gt;store&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="nx"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&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;create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; (definitely not evil)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stagesCompleted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;discover&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;persons&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;create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lovesRedux&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;you bet!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;]))&lt;/span&gt;

&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 'MegaCorp (definitely not evil)'&lt;/span&gt;
&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stagesCompleted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;discover&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; true&lt;/span&gt;
&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;persons&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;lovesRedux&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 'you bet!'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;h3&gt;
  
  
  Advanced usage: write once, reduce anywhere
&lt;/h3&gt;

&lt;p&gt;Sometimes you'll have some logic that is more bespoke.&lt;/p&gt;

&lt;p&gt;With Redux-Leaves, you can &lt;a href="https://redux-leaves.js.org/docs/api/leaf-reducers"&gt;write this custom logic once&lt;/a&gt;, and then use it at any arbitrary leaf of state.&lt;/p&gt;

&lt;p&gt;You can play around with this advanced usage on &lt;a href="https://runkit.com/richardcrng/no-boilerplate-with-redux-leaves-advanced-usage"&gt;RunKit&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;reduxLeaves&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;redux-leaves&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// break-even at arbitrary leaf state&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;breakEven&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;leafState&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;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;leafState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;revenue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;leafState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;costs&lt;/span&gt; &lt;span class="c1"&gt;// set revenue property equal to the costs property&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// set all properties at arbitrary leaf state&lt;/span&gt;
&lt;span class="c1"&gt;//   payload received will be the value to set&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;setAll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;leafState&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;leafKeys&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;leafState&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;newEntries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;leafKeys&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="nx"&gt;key&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="k"&gt;return&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;newEntries&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// set some property for all elements of an array&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;setEach&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;leafState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;prop&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="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;leafState&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;element&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;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;prop&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="na"&gt;argsToPayload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prop&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;prop&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customReducers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;breakEven&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setAll&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setEach&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;reducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;reduxLeaves&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="nx"&gt;customReducers&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;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createStore&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="c1"&gt;// make both agency and client breakeven&lt;/span&gt;
&lt;span class="nx"&gt;store&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="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;agency&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;breakEven&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nx"&gt;store&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="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;breakEven&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="c1"&gt;// mark all stages complete&lt;/span&gt;
&lt;span class="nx"&gt;store&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="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stagesCompleted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAll&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="c1"&gt;// give each person a happy status&lt;/span&gt;
&lt;span class="nx"&gt;store&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="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;persons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;happy&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;h2&gt;
  
  
  What next?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;In this post, I argued that a lot of your Redux boilerplate can be entirely eliminated by using &lt;a href="https://redux-leaves.js.org"&gt;Redux-Leaves&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The typical approaches streamline handling specific reducer cases, action types and action creators, but there's still a scaling problem. Choose between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;very large&lt;/em&gt; reducer files; or&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;very many&lt;/em&gt; reducer files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With Redux-Leaves, you can avoid choosing either: it's two lines of setup, one of which is an import.&lt;/p&gt;

&lt;h3&gt;
  
  
  Discussion points
&lt;/h3&gt;

&lt;p&gt;Some advocate an eventful model of Redux actions. If you have opinions on that, I'd love to hear from you!&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://dev.to/richardcrng/redux-command-actions-that-scale-without-boilerplate-1p04"&gt;In a previous post and discussion thread&lt;/a&gt;, I've outlined how I think this might: (a) not be necessary, since Redux-Leaves solves typical command action problems: and (b) how Redux-Leaves might be able to accommodate eventful action modelling. Please leave a comment!)&lt;/p&gt;

&lt;h3&gt;
  
  
  Read The Docs
&lt;/h3&gt;

&lt;p&gt;Please &lt;a href="https://redux-leaves.js.org"&gt;read the docs&lt;/a&gt; and let me know any feedback you have about the library or its documentation - I'm on &lt;a href="https://twitter.com/richardcrng"&gt;Twitter&lt;/a&gt;, or you can &lt;a href="https://github.com/richardcrng/redux-leaves"&gt;file an issue on GitHub&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>redux</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>Redux command actions that scale without boilerplate</title>
      <dc:creator>Richard Ng</dc:creator>
      <pubDate>Fri, 29 Nov 2019 13:47:08 +0000</pubDate>
      <link>https://dev.to/richardcrng/redux-command-actions-that-scale-without-boilerplate-1p04</link>
      <guid>https://dev.to/richardcrng/redux-command-actions-that-scale-without-boilerplate-1p04</guid>
      <description>&lt;p&gt;&lt;b&gt;Should I read this post?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;I think that you are more likely to find value in reading this post if you are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Trying to cut down on your Redux boilerplate; or&lt;/li&gt;
&lt;li&gt;Interested in improving your Redux architecture or file structure; or&lt;/li&gt;
&lt;li&gt;Trying to navigate Redux actions as 'commands' versus 'events'.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Key takeaways are at the foot of this post.&lt;/p&gt;






&lt;p&gt;I recently watched a recording of a great talk by &lt;a href="https://twitter.com/YazanAlaboudi"&gt;Yazan Alaboudi&lt;/a&gt;, &lt;a href="https://youtu.be/K6OlKeQRCzo?t=2626"&gt;'Our Redux Anti Pattern: A guide to predictable scalability'&lt;/a&gt; (slides &lt;a href="https://rangle.slides.com/yazanalaboudi/deck#/"&gt;here&lt;/a&gt;). I really love hearing and reading about people's thoughts on Redux architecture, as something I've thought a lot about.&lt;/p&gt;

&lt;p&gt;In the talk, Yazan makes an excellent case for two points:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Writing Redux actions as commands&lt;sup&gt;1&lt;/sup&gt; is an anti-pattern; and&lt;/li&gt;
&lt;li&gt;A well-written Redux action should represent a business event.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this particular post, I'm going to respond to the first of these points, with a view to discussing the second in a separate post.&lt;/p&gt;

&lt;p&gt;Here, my core contention is this: &lt;strong&gt;Redux-Leaves solves most - and perhaps all - of Yazan's 'anti-pattern' criticisms of command actions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'll do this in two parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Firstly, I'll outline Yazan's case against command actions; and&lt;/li&gt;
&lt;li&gt;Secondly, I'll demonstrate how Redux-Leaves solves those problems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is Yazan's case against command actions?
&lt;/h2&gt;

&lt;p&gt;I recommend watching &lt;a href="https://youtu.be/K6OlKeQRCzo?t=3182"&gt;Yazan's own explanation&lt;/a&gt;, but below I will outline my interpretation of what he says.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example code
&lt;/h4&gt;

&lt;p&gt;Yazan provides some examples of &lt;a href="https://rangle.slides.com/yazanalaboudi/deck#/31"&gt;command actions&lt;/a&gt; and their &lt;a href="https://rangle.slides.com/yazanalaboudi/deck#/32"&gt;consequences&lt;/a&gt;:&lt;/p&gt;

&lt;h5&gt;
  
  
  Command Action Example (Redux setup)
&lt;/h5&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// in scoreboardReducer.js&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;INITIAL_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;home&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="na"&gt;away&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;function&lt;/span&gt; &lt;span class="nx"&gt;scoreboardReducer&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="nx"&gt;INITIAL_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="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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;INCREMENT_SCORE&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;scoringSide&lt;/span&gt; &lt;span class="o"&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="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;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;scoringSide&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;scoringSide&lt;/span&gt;&lt;span class="p"&gt;]&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="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="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;//in crowdExcitmentReducer.js&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;INITIAL_STATE&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="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;crowdExcitementReducer&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="nx"&gt;INITIAL_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="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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;INCREASE_CROWD_EXCITEMENT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;state&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;return&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  Command Action Consequences (Component dispatching)
&lt;/h5&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// in GameComponent&lt;/span&gt;
  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;GameComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;scoreGoal&lt;/span&gt;&lt;span class="p"&gt;()&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="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;INCREMENT_SCORE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;scoringSide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;home&lt;/span&gt;&lt;span class="dl"&gt;"&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="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;INCREASE_CROWD_EXCITEMENT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="c1"&gt;// potentially more dispatches&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&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;&lt;a href="https://rangle.slides.com/yazanalaboudi/deck#/33"&gt;In a key slide, he then lays out some costs&lt;/a&gt; that he sees in these command-oriented examples:&lt;/p&gt;

&lt;blockquote&gt;
&lt;h4&gt;
  
  
  Disadvantages of Command actions
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;does not capture business semantics&lt;/li&gt;
&lt;li&gt;actions are coupled to reducers&lt;/li&gt;
&lt;li&gt;too many actions are firing&lt;/li&gt;
&lt;li&gt;unclear why state is changing&lt;/li&gt;
&lt;li&gt;leads to a lot of boilerplate&lt;/li&gt;
&lt;li&gt;does not scale&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here are my observations on each of these (with the exception of 'business semantics', which I'll tackle in a separate post):&lt;/p&gt;

&lt;h3&gt;
  
  
  Actions are coupled to reducers
&lt;/h3&gt;

&lt;p&gt;I think that, when it comes to the example code provided by Yazan, it's extremely fair to note that actions are coupled to reducers. The &lt;code&gt;"INCREMENT_SCORE"&lt;/code&gt; action type looks entirely coupled to the &lt;code&gt;scoreboardReducer&lt;/code&gt;, and the &lt;code&gt;"INCREASE_CROWD_EXCITEMENT"&lt;/code&gt; looks entirely coupled to the &lt;code&gt;crowdExcitementReducer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is not a good pattern because it means we have extremely low code reusability. If I want to increment something else, like the stadium audience size, I need to use &lt;em&gt;another&lt;/em&gt; action type, &lt;code&gt;"INCREMENT_AUDIENCE_SIZE"&lt;/code&gt;, even though the resulting change in state is going to be extremely similar.&lt;/p&gt;

&lt;h3&gt;
  
  
  Too many actions are firing
&lt;/h3&gt;

&lt;p&gt;Again, when it comes to Yazan's example code, I think it's fair to note that more actions are being dispatched in the &lt;code&gt;scoreGoal&lt;/code&gt; function that &lt;em&gt;feels&lt;/em&gt; necessary. If a goal has been scored, a single thing has happened, and yet we're triggering multiple actions.&lt;/p&gt;

&lt;p&gt;This is not a good pattern because it will clog up your Redux DevTools with lots of noise, and potentially could cause some unnecessary re-renders with your Redux state updating multiple times instead of doing a single large update.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unclear why state is changing
&lt;/h3&gt;

&lt;p&gt;I'm not convinced that this is a big problem. For me, in Yazan's example code, it's not too difficult for me to make the link from &lt;code&gt;scoreGoal&lt;/code&gt; to &lt;code&gt;"INCREASE_SCORE"&lt;/code&gt; and &lt;code&gt;"INCREASE_CROWD_EXCITEMENT"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To the extent that the 'why' is unclear, I think that this can be solved by &lt;a href="https://blog.codinghorror.com/code-tells-you-how-comments-tell-you-why/"&gt;better-commented code&lt;/a&gt; - which isn't a situation unique to command actions in Redux, but something that applies to all imperatively-flavoured code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Leads to a lot of boilerplate /  Does not scale
&lt;/h3&gt;

&lt;p&gt;I think these two are both legitimate concerns (and, at core, the same concern): if, every time we decide we want to effect a new change in state, we have to decide on a new action type and implement some new reducer logic, we will quickly get a profileration of Redux-related code, and this means that it doesn't scale very well as an approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does Redux-Leaves solve these problems?
&lt;/h2&gt;

&lt;p&gt;First, let's look at some example code, equivalent to the previous examples:&lt;/p&gt;

&lt;h5&gt;
  
  
  Redux-Leaves setup
&lt;/h5&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// store.js&lt;/span&gt;

  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createStore&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;redux&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;reduxLeaves&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;redux-leaves&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&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;crowdExcitment&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="na"&gt;scoreboard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;home&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="na"&gt;away&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="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;reducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;reduxLeaves&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;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createStore&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="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  Component dispatching
&lt;/h5&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// in GameComponent&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;bundle&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;redux-leaves&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;actions&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;./path/to/store&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;GameComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;scoreGoal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// create and dispatch actions to increment both:&lt;/span&gt;
      &lt;span class="c1"&gt;//    * storeState.scoreboard.home&lt;/span&gt;
      &lt;span class="c1"&gt;//    * storeState.crowdExcitement&lt;/span&gt;
      &lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scoreboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;home&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&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="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;crowdExcitement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&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="c1"&gt;// potentially more actions&lt;/span&gt;
      &lt;span class="p"&gt;]));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;//...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here's an &lt;a href="https://runkit.com/richardcrng/soccer-game-app-with-redux-leaves"&gt;interactive RunKit playground&lt;/a&gt; with similar code for you to test and experiment with.&lt;/p&gt;

&lt;p&gt;Hopefully, in comparison to the example of more typical command actions given by Yazan, this Redux-Leaves setup speaks for itself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only one initial state and reducer to handle&lt;/li&gt;
&lt;li&gt;No more writing reducers manually yourself&lt;/li&gt;
&lt;li&gt;No more manual case logic manually yourself&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll also now cover how it addresses each of the specific problems articulated above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Actions are &lt;em&gt;no longer&lt;/em&gt; coupled to reducers&lt;/li&gt;
&lt;li&gt;Too many actions? Bundle them into one&lt;/li&gt;
&lt;li&gt;Extreme clarity on what state is changing&lt;/li&gt;
&lt;li&gt;Incredibly minimal boilerplate&lt;/li&gt;
&lt;li&gt;Simple to scale&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Actions are &lt;em&gt;no longer&lt;/em&gt; coupled to reducers
&lt;/h3&gt;

&lt;p&gt;Redux-Leaves gives you an &lt;a href="https://redux-leaves.js.org/docs/defaults/increment"&gt;&lt;code&gt;increment&lt;/code&gt;&lt;/a&gt; action creator out-of-the-box, that &lt;a href="https://redux-leaves.js.org/docs/api/actions"&gt;can be used at an arbitrary state path from &lt;code&gt;actions&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;To increment...&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;create&lt;/code&gt; and &lt;code&gt;dispatch&lt;/code&gt; this action...&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;storeState.crowdExcitement&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;actions.crowdExcitement.create.increment()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;storeState.scoreboard.away&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;actions.scoreboard.away.create.increment()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;storeState.scoreboard.home&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;actions.scoreboard.home.create.increment()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You get a whole bunch of other &lt;a href="https://redux-leaves.js.org/docs/defaults/overview"&gt;default action creators&lt;/a&gt; too, which can all be effected at an arbitrary leaf of your state tree.&lt;/p&gt;

&lt;h3&gt;
  
  
  Too many actions? Bundle them into one
&lt;/h3&gt;

&lt;p&gt;Redux-Leaves has a named &lt;code&gt;bundle&lt;/code&gt; export, which accepts an array of actions created by Redux-Leaves, and returns a &lt;em&gt;single action&lt;/em&gt; that can effect all those changes in a single dispatch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;createStore&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;redux&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;reduxLeaves&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;bundle&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;redux-leaves&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&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;crowdExcitment&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="na"&gt;scoreboard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;home&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="na"&gt;away&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="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;reducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;reduxLeaves&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;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createStore&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;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="cm"&gt;/*
    {
      crowdExcitement: 0,
      scoreboard: {
        home: 0,
        away: 0
      }
    }
  */&lt;/span&gt;

  &lt;span class="nx"&gt;store&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="nx"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scoreboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;home&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&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="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scoreboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;away&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&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="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;crowdExcitement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&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="mi"&gt;9001&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;]))&lt;/span&gt;

  &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="cm"&gt;/*
    {
      crowdExcitement: 9001,
      scoreboard: {
        home: 7,
        away: 1
      }
    }
  */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;h3&gt;
  
  
  Extreme clarity on what state is changing
&lt;/h3&gt;

&lt;p&gt;In Yazan's example of command actions, it's not obvious how the overall store state is going to be affected by the dispatches - which score is being incremented in which bit of state?&lt;/p&gt;

&lt;p&gt;With Redux-Leaves, the &lt;a href="https://redux-leaves.js.org/docs/api/actions"&gt;&lt;code&gt;actions&lt;/code&gt; API&lt;/a&gt; means that you are extremely explicit in which state is being changed: you use a property path to the state you want to create an action at, just as you would if you were looking at your state tree and describing which bit of state that you wanted to effect.&lt;/p&gt;

&lt;p&gt;(This isn't addressing &lt;em&gt;quite&lt;/em&gt; the same point Yazan makes, which I think is asking, 'but &lt;em&gt;why&lt;/em&gt; are we increasing crowd excitement?' - but, as I indicated in discussing that point, I think it's the responsibility of the developer to make the &lt;em&gt;why&lt;/em&gt; of a command clear through a comment, if needed.)&lt;/p&gt;

&lt;h3&gt;
  
  
  Incredibly minimal boilerplate
&lt;/h3&gt;

&lt;p&gt;Here's what we need to do to get our root reducer and action creators:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;reduxLeaves&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;redux-leaves&lt;/span&gt;&lt;span class="dl"&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;reducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;reduxLeaves&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That's it. Two lines, one of which is an import. No faffing around with writing action constants, creators or reducer &lt;code&gt;case&lt;/code&gt; statements yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple to scale
&lt;/h3&gt;

&lt;p&gt;Suppose we want to introduce some state to keep track of team names.&lt;/p&gt;

&lt;p&gt;All we need to do is to change our initial state...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import reduxLeaves from 'redux-leaves'
&lt;/span&gt;
const initialState = {
  crowdExcitement: 0,
  scoreboard: {
    home: 0,
    away: 0
  },
&lt;span class="gi"&gt;+  teams: {
+    home: 'Man Red',
+    away: 'Man Blue'
&lt;/span&gt;  }
&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;const [reducer, actions] = reduxLeaves(initialState)
const store = createStore(reducer)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;... and then we can straight away start dispatching actions to update that state, without having to write any further reducers, action creators or action types:&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;store&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="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;teams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;away&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;London Blue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;teams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;away&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 'London Blue'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You should watch &lt;a href="https://youtu.be/K6OlKeQRCzo?t=2626"&gt;Yazan's talk&lt;/a&gt; and look at &lt;a href="https://rangle.slides.com/yazanalaboudi/deck#/"&gt;his slides&lt;/a&gt;, both are really thoughtful&lt;/li&gt;
&lt;li&gt;Yazan makes a strong case against how Redux command actions are typically written&lt;/li&gt;
&lt;li&gt;I think that &lt;a href="https://redux-leaves.js.org"&gt;Redux-Leaves&lt;/a&gt; solves most of those problems, if not all&lt;/li&gt;
&lt;/ul&gt;



&lt;h4&gt;
  
  
  Endnotes
&lt;/h4&gt;

&lt;p&gt;&lt;sup&gt;1&lt;/sup&gt; An Redux action can be considered a command if it expresses intent to &lt;em&gt;do something&lt;/em&gt;. Examples given by Yazan are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SEND_CONFIRMATION&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="na"&gt;type&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_BILLING&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="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SEND_LETTER&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="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INCREMENT_SCORE&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="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INCREASE_CROWD_EXCITEMENT&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;small&gt;MAIN&lt;/small&gt;&lt;/p&gt;

</description>
      <category>redux</category>
      <category>javascript</category>
      <category>react</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Strangers on the internet who inspired my open-source library</title>
      <dc:creator>Richard Ng</dc:creator>
      <pubDate>Thu, 28 Nov 2019 11:49:10 +0000</pubDate>
      <link>https://dev.to/richardcrng/strangers-on-the-internet-who-inspired-my-open-source-library-27cn</link>
      <guid>https://dev.to/richardcrng/strangers-on-the-internet-who-inspired-my-open-source-library-27cn</guid>
      <description>&lt;p&gt;&lt;b&gt;Should I read this post?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;I think that you are more likely to find value in reading this post if you are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Interested in my experience of learning from others; or&lt;/li&gt;
&lt;li&gt;Curious about the history of &lt;a href="https://redux-leaves.js.org"&gt;Redux-Leaves&lt;/a&gt;; or&lt;/li&gt;
&lt;li&gt;Made happy by expressions of gratitude to strangers on the internet.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;A habit that I picked up during my academic studies is giving due credit to individuals who have been influential in shaping my thoughts, so I thought that it would be.&lt;/p&gt;

&lt;p&gt;This occurred to me as I was preparing to give a couple of talks about an open-source library that I've written, &lt;a href="https://redux-leaves.js.org"&gt;Redux-Leaves&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Right now, I don't actually want to talk about myself or Redux-Leaves, but about how &lt;em&gt;strangers on the internet who I have never met in real life&lt;/em&gt; made Redux-Leaves possible - not by contributing code to the repository, but by contributing ideas, blogs and talks to the public domain.&lt;/p&gt;

&lt;p&gt;I think the time pressure in a talk would make it difficult for me to acknowledge those who have influenced my thought in a sufficiently eloquent or detailed way, and so I've decided to write up those thoughts in a blog post instead (and follow their example of putting things in the public domain!).&lt;/p&gt;

&lt;p&gt;In no particular order, these individuals are are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dan Abramov&lt;/li&gt;
&lt;li&gt;Mark Erikson&lt;/li&gt;
&lt;li&gt;Shawn Wang&lt;/li&gt;
&lt;li&gt;Kent C. Dodds&lt;/li&gt;
&lt;li&gt;Tyler McGinnis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In some of these cases, I might be giving credit to an individual when it might actually be more appropriate to give it to a group of which said individual happens to be most prominent. This is not intentional and I apologise for people whom I have overlooked.&lt;/p&gt;

&lt;p&gt;In writing this up, I've also realised that I'm missing out on a lot of learning by doing a &lt;small&gt;VERY BAD JOB&lt;/small&gt; at finding diverse voices to learn from. So, selfishly, I'd love it if you would &lt;a href="https://twitter.com/richardcrng"&gt;tweet me&lt;/a&gt; recommendations on individuals, newsletters or blogs to follow, particularly those more likely to have diverse viewpoints.&lt;/p&gt;

&lt;p&gt;Without further ado, here's how each of those individuals contributed in some way to me writing &lt;a href="https://redux-leaves.js.org"&gt;Redux-Leaves&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dan Abramov (&lt;a href="https://twitter.com/dan_abramov"&gt;@dan_abramov&lt;/a&gt;)
&lt;/h2&gt;

&lt;p&gt;I'd like to credit Dan with three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;For planting the seed of my 'a-ha!' moment;&lt;/li&gt;
&lt;li&gt;For creating Redux; and&lt;/li&gt;
&lt;li&gt;For giving great talks generally.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Planting the seed of my 'a-ha!' moment
&lt;/h3&gt;

&lt;p&gt;What I say below will make a lot more sense if you watch at least the one minute of footage where Dan &lt;a href="https://youtu.be/dpw9EHDh2bM?t=1291"&gt;introduces the React useState hook&lt;/a&gt;, although I recommend watching more of the talk (because it's great!).&lt;/p&gt;

&lt;p&gt;The way that Dan introduced &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;setName&lt;/code&gt; as a pair made me realise that a Redux store's &lt;code&gt;reducer&lt;/code&gt;, and the &lt;code&gt;actions&lt;/code&gt; dispatched to it, could be a pair returned from a single function. A reducer needs to be closely related to the actions dispatched to it.&lt;/p&gt;

&lt;p&gt;This influence is clear when you compare the signatures for &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;reduxLeaves&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="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;setState&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="nx"&gt;initialValue&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;reducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;reduxLeaves&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That 'a-ha!' moment for an API which gave you both &lt;code&gt;reducer&lt;/code&gt; and &lt;code&gt;actions&lt;/code&gt; - I didn't have any implementation specifics, just the high-level API desire - eventually led to the development of &lt;a href="https://redux-leaves.js.org"&gt;Redux-Leaves&lt;/a&gt;, which I'll write about in more technical detail another time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Redux
&lt;/h3&gt;

&lt;p&gt;Another great talk given by Dan was the one where he &lt;a href="https://youtu.be/xsSnOQynTHs?t=664"&gt;introduced Redux&lt;/a&gt; (reducers + flux). Clearly, as a library which came out of my experiences with Redux, Redux-Leaves is also existentially indebted to Redux, although that might be obvious and non-interesting.&lt;/p&gt;

&lt;p&gt;It might be worth noting that Redux-Leaves uses a cursor-ish approach, which &lt;a href="https://github.com/reduxjs/redux/issues/155#issuecomment-113898044"&gt;Dan might not have intended for Redux&lt;/a&gt;, so he might regard me as doing something completely barbaric with Redux-Leaves. I won't put words in his mouth here, though, as I think &lt;a href="https://twitter.com/dan_abramov/status/1191487232038883332?lang=en"&gt;Dan's opinions on Redux may have changed since he created it&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Giving great talks
&lt;/h3&gt;

&lt;p&gt;If it wasn't obvious from the fact that I've linked to two of his talks, I think Dan does really great talks. I think that they have a nice theatricality that brings in the audience, and it also looks like he just really enjoys giving them, which itself makes them enjoyable to watch.&lt;/p&gt;

&lt;p&gt;I think it's partly Dan's talks that have inspired me to start giving my own talks - which is why it's also great that Dan has &lt;a href="https://overreacted.io/preparing-for-tech-talk-part-3-content/"&gt;written about how he prepares for his talks&lt;/a&gt;.&lt;/p&gt;



&lt;h2&gt;
  
  
  Mark Erikson (&lt;a href="https://twitter.com/acemarke"&gt;@acemarke&lt;/a&gt;)
&lt;/h2&gt;

&lt;p&gt;I'd like to credit Mark with three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An inspiring dedication to documentation;&lt;/li&gt;
&lt;li&gt;Remarkably thorough writings on and around Redux; and&lt;/li&gt;
&lt;li&gt;
Maintaining Redux entirely outside his day job.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Dedication to documentation
&lt;/h3&gt;

&lt;p&gt;Mark is &lt;em&gt;seriously&lt;/em&gt; &lt;a href="https://github.com/reduxjs/redux/issues/3615"&gt;committed to good documentation&lt;/a&gt;. It's something that has inspired me with Redux-Leaves - I'm aiming to hit the same high bar of documentation. (I've even followed Mark in using &lt;a href="https://docusaurus.io/"&gt;Docusaurus&lt;/a&gt;.)&lt;/p&gt;

&lt;h3&gt;
  
  
  Writings on and around Redux
&lt;/h3&gt;

&lt;p&gt;Mark has pulled together some really amazing writings on Redux - the two most significant being:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-1/"&gt;Idiomatic Redux: The Tao of Redux, Part 1 - Implementation and Intent&lt;/a&gt;; and&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-2/"&gt;https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-2/&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's certainly not &lt;em&gt;necessary&lt;/em&gt; to read these before using Redux or Redux-Leaves, but I think if you're serious about deeply understanding Redux, it's highly advisable to read them.&lt;sup&gt;1&lt;/sup&gt; I can't strongly enough recommend Mark's posts for how well-written, researched and thought provoking they are.&lt;/p&gt;

&lt;h3&gt;
  
  
  Maintaining Redux
&lt;/h3&gt;

&lt;p&gt;Mark also does a really heroic job of maintaining Redux - it's not his day job, he does it in his free time. I for one absolutely &lt;em&gt;love&lt;/em&gt; the React-Redux hooks, released in v7.1.0, and rejoice in the prospect of never having to write another &lt;code&gt;connect&lt;/code&gt;. Although the hooks seemed to appear like magic into my code with the update, an incredible amount  of &lt;a href="https://github.com/reduxjs/react-redux/issues/1179"&gt;discussion&lt;/a&gt; and &lt;a href="https://github.com/reduxjs/react-redux/issues/1252"&gt;work&lt;/a&gt; went into them.&lt;/p&gt;

&lt;p&gt;A big milestone recently was the official release of &lt;a href="https://redux-toolkit.js.org/"&gt;Redux Toolkit&lt;/a&gt;, which deserves to be looked at by all Redux developers. In particular, I'm a fan of its &lt;a href="https://redux-toolkit.js.org/api/configureStore"&gt;&lt;code&gt;configureStore&lt;/code&gt;&lt;/a&gt; export as a big improvement on the API of &lt;a href="https://redux.js.org/api/createstore"&gt;&lt;code&gt;createStore&lt;/code&gt;&lt;/a&gt; from the core Redux library.&lt;/p&gt;

&lt;p&gt;Predictably, I personally prefer &lt;a href="https://redux-leaves.js.org"&gt;Redux-Leaves&lt;/a&gt; to &lt;a href="https://redux-toolkit.js.org/api/createSlice"&gt;&lt;code&gt;createSlice&lt;/code&gt;&lt;/a&gt;, but I'd urge everybody to try out Redux Toolkit and see how they find it.&lt;/p&gt;



&lt;h2&gt;
  
  
  Kent C. Dodds (&lt;a href="https://twitter.com/kentcdodds"&gt;@kentcdodds&lt;/a&gt;)
&lt;/h2&gt;

&lt;p&gt;Kent's writings on testing have made it significantly easier for me to refactor and publish updates to Redux-Leaves.&lt;/p&gt;

&lt;p&gt;In particular, Kent brought two particular ideas to my attention: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://kentcdodds.com/blog/write-tests"&gt;Write tests. Not too many. Mostly integration.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://twitter.com/kentcdodds/status/977018512689455106"&gt;The more your tests resemble the way your software is used, the more confidence they can give you.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What does this mean in practice?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://redux-leaves.js.org"&gt;Redux-Leaves&lt;/a&gt; as a library has very few unit tests, and quite a lot of integration tests, most of which are tests of documentation examples - i.e., tests that resemble the way the library is likely to be used.&lt;/p&gt;

&lt;p&gt;The library has been through two refactors of note since I first wrote it. In the first refactor, I ended up dumping a lot of unit tests that were &lt;a href="https://kentcdodds.com/blog/testing-implementation-details"&gt;testing implementation&lt;/a&gt; and therefore completely wrecked by the refactor. I felt no qualms about this - the intended, documented use was covered by the integration tests, that were still passing after the refactor. In the second refactor, I don't remember having to rewrite or delete many tests at all, since the remaining tests were pretty much all about usage and not about implementation.&lt;/p&gt;

&lt;p&gt;I now try to follow a process of 'Documentation-Driven Development' with Redux-Leaves. I start by writing the documentation for a new feature, and then I write tests for the documented usage that are agnostic about implementation, and &lt;em&gt;then&lt;/em&gt; I start writing code. It's a marrying together of what Kent writes about testing with my dedication to documentation as inspired by Mark Erikson.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shawn Wang (&lt;a href="https://twitter.com/swyx"&gt;@swyx&lt;/a&gt;)
&lt;/h2&gt;

&lt;p&gt;Shawn is famous for writing about &lt;a href="https://www.swyx.io/writing/learn-in-public"&gt;learning in public&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'm still trying to improve on this - for example, I sometimes worry about bothering people or looking like a shameless self-promoter, and Redux-Leaves has &lt;em&gt;mostly&lt;/em&gt; been hacked together by myself, for myself - but I have nonetheless managed to gain &lt;em&gt;some&lt;/em&gt; benefits from it. In the very early days of the library, I managed to get some really valuable feedback (with one particular signpost to &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy"&gt;Proxies&lt;/a&gt; leading to a major rewrite of the library).&lt;/p&gt;

&lt;p&gt;This blog post itself is an example of me trying to be better at learning in public!&lt;/p&gt;

&lt;h2&gt;
  
  
  Tyler McGinnis (&lt;a href="https://twitter.com/tylermcginnis"&gt;@tylermcginnis&lt;/a&gt;)
&lt;/h2&gt;

&lt;p&gt;I subscribe to Tyler's &lt;a href="https://tylermcginnis.com/newsletter/"&gt;weekly Javascript newsletter&lt;/a&gt;, which I like because it keeps a pipeline of cool projects coming into my inbox. I look at them, and I feel inspired to keep working on my own projects, the most major of which is - of course - &lt;a href="https://redux-leaves.js.org"&gt;Redux-Leaves&lt;/a&gt;!&lt;/p&gt;




&lt;p&gt;What do I hope are the key takeaways from this?&lt;/p&gt;

&lt;p&gt;Well, I'd like to think that this post helps encourage somebody to keep learning and working on their project, whether that be an open-source library like &lt;a href="https://redux-leaves.js.org"&gt;Redux-Leaves&lt;/a&gt; or something else.&lt;/p&gt;

&lt;p&gt;The individuals I've cited all have pretty high-profiles, in that they all have at least 10k Twitter followers, so they &lt;em&gt;certainly&lt;/em&gt; don't need me to promote them - but, even so, I think it's nice to thank people who've helped you, so I also would like to think that I've achieved that.&lt;/p&gt;

&lt;p&gt;Finally, because I like the &lt;a href="https://en.wikipedia.org/wiki/Rule_of_three_(writing)"&gt;rule of three&lt;/a&gt;, I'll circle back to something I've alluded to earlier: I'm aware of an extreme lack of diversity in the figures I've cited here, which means that I'm missing out on a lot of learning. I want to fix this shortcoming. If you can think of anybody that I should follow, please &lt;a href="https://twitter.com/richardcrng"&gt;tweet me&lt;/a&gt; a suggestion!&lt;/p&gt;



&lt;h4&gt;
  
  
  Endnotes
&lt;/h4&gt;

&lt;p&gt;&lt;sup&gt;1&lt;/sup&gt; One thing that comes out of Mark's posts is that there are many &lt;em&gt;technically valid&lt;/em&gt; ways to write Redux code, but not all of these might be intended ways to write it. For example, &lt;a href="https://redux-leaves.js.org"&gt;Redux-Leaves&lt;/a&gt; is a &lt;a href="https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-2/#reducer-variations"&gt;cursor-ish library&lt;/a&gt; that &lt;a href="https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-2/#action-tense-and-setters-vs-events"&gt;is more suited to modelling setters than events&lt;/a&gt;, which is technically valid - but this is not necessarily the way that Redux is intended to be used.&lt;/p&gt;

&lt;p&gt;I had a short conversation with Mark about this, where he said: (a) "it's a legitimate approach from a technical standpoint, but not how we're trying to encourage people to think about things"; and (b) "if you've found a variation on a usage pattern that works well for you, go ahead and do that".&lt;/p&gt;

&lt;p&gt;So, &lt;a href="https://en.wikipedia.org/wiki/Caveat_emptor"&gt;&lt;em&gt;caveat emptor&lt;/em&gt;&lt;/a&gt; with &lt;a href="https://redux-leaves.js.org"&gt;Redux-Leaves&lt;/a&gt;, but  I will write a separate covering my thoughts in more detail at some point. Acknowledging that Redux-Leaves might not be following an intended usage pattern for Redux, I still find that the benefits for me when I use it greatly outweigh the costs. &lt;small&gt;MAIN&lt;/small&gt;&lt;/p&gt;

</description>
      <category>redux</category>
      <category>opensource</category>
      <category>javascript</category>
      <category>react</category>
    </item>
  </channel>
</rss>
