<?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: Jason M</title>
    <description>The latest articles on DEV Community by Jason M (@ingrey1).</description>
    <link>https://dev.to/ingrey1</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%2F301494%2Fedc0a7a7-7324-4c17-82a9-8f77c7f36ad7.jpeg</url>
      <title>DEV Community: Jason M</title>
      <link>https://dev.to/ingrey1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ingrey1"/>
    <language>en</language>
    <item>
      <title>Simplying State Management with Immer: Some Thoughts</title>
      <dc:creator>Jason M</dc:creator>
      <pubDate>Sun, 31 May 2020 23:53:56 +0000</pubDate>
      <link>https://dev.to/ingrey1/simplying-state-management-with-immer-some-thoughts-2b50</link>
      <guid>https://dev.to/ingrey1/simplying-state-management-with-immer-some-thoughts-2b50</guid>
      <description>&lt;p&gt;Not sure about the rest of you, but I find that with any mildly complex state in react / redux applications, updating state for objects deeper inside the state can be a pain.&lt;/p&gt;

&lt;p&gt;Here's some state:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqo3tagy6nv18qjsnszus.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqo3tagy6nv18qjsnszus.png" alt="some state"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Suppose we want to make a change to the description for item 3 (id) in purchase 7 for account 1. Without a helper library, we'd do something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyyj5axyz12xaqggbacnf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyyj5axyz12xaqggbacnf.png" alt="a complicated way to update state"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All of this just to update a single field. The excess spreading makes the code hard to understand, and also introduces more opportunities to mess up and introduce bugs. Wouldn't it be better if we could just do something like this?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft5p0gozlonuq2fzurmzn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft5p0gozlonuq2fzurmzn.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This code is a lot cleaner, more intelligible, and leaves less room for introducing bugs. Unfortunately, when we're working with state in react and redux, we need to avoid mutating state directly, so without a helping hand, we cant use the latter code snippet. Fortunately, Immer (a javascript immutability library), can provide us with that helping hand.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftzym38ndo225tlkjvgo6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftzym38ndo225tlkjvgo6.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Rails: Using a custom serializer to serialize a collection of active record model instances</title>
      <dc:creator>Jason M</dc:creator>
      <pubDate>Wed, 18 Mar 2020 02:39:31 +0000</pubDate>
      <link>https://dev.to/ingrey1/rails-using-a-custom-serializer-to-serialize-a-collection-of-active-record-model-instances-3khh</link>
      <guid>https://dev.to/ingrey1/rails-using-a-custom-serializer-to-serialize-a-collection-of-active-record-model-instances-3khh</guid>
      <description>&lt;p&gt;So, serializers provide a standardized way to shape and characterize the data an endpoint needs to return based on a given response. There are a number of ruby gems that do serialization. One popular gem is 'active_model_serializers'.&lt;/p&gt;

&lt;p&gt;If you have the active_model_serializers gem enabled in your rails app, and your endpoint renders some json, such as: 'render json: iAmAnActiveRecordBookInstance' -- well if you have a serializer in the serializers folder with the same name as the model instance, rails will make use of it, and provide the serialized data of your book, based on that serializer.&lt;/p&gt;

&lt;p&gt;However, sometimes we may want to include or exclude information for a particular model instance based on relationships to other models. And, in this situation, it's likely we're going to have custom serializers that we wish to employ in the given endpoint. There is a simple way to do this:&lt;/p&gt;

&lt;p&gt;render json: myModel, serializer: mySerializer&lt;/p&gt;

&lt;p&gt;In this way we can utilize a custom serializer&lt;/p&gt;

&lt;p&gt;However, often we have a list of active record associations we wish to serialize. If we just wish to let rails employ the default serializer action, then we can do something like this:  render json: myModelInstance.all   &lt;/p&gt;

&lt;p&gt;In the above case, rails will look in the serializers folder for a serializer with the same name as the model instance, and apply it to all the items in the active record 'list'. This is fine if what you want are all your instances to serialize via the default serializer for the model. However, sometimes we don't want that: we want a custom serializer.&lt;/p&gt;

&lt;p&gt;If you try this, you will run into an error: 'render json: Book.all, serializer: customBookSerializer'&lt;/p&gt;

&lt;p&gt;So, why does this fail, just because we specify the serializer? A collection of instances is not an instance: A serializer for a collection of instances is not a serializer for an instance. When we left it to rails' default behavior, there is a check for whether this is just an instance of a model, or a collection of model instances, and rails would employ a collection serializer and the collection's instance serializer. But if we specify our serializer, we are taking control of the serialization process, and we need to be a little bit more specific if we want our custom serializer to apply to a collection of objects of a given kind.&lt;/p&gt;

&lt;p&gt;So, here's how you make use of a custom serializer for a collection of active record model instances: render json: Book.all, serialize_each: customSerializer&lt;/p&gt;

&lt;p&gt;Sometimes, your serializers may need information in order to serialize the information you need. You can pass in information, such as a userId or an itemId in this way:&lt;/p&gt;

&lt;p&gt;'render json: Book.all, serialize_each: customSerializer, additionalProperty: additionalPropertyValue&lt;/p&gt;

&lt;p&gt;Inside of your serializer, you can access additionalProperty as 'instance_options[:additionalProperty]'.   &lt;/p&gt;

&lt;p&gt;You might wonder, "why would I ever need to pass information to my serializer, if the relationships are set up correctly?" You might not need to. But one very useful case is where you have a many-to-many relationship with another model, via a join table, and you need to retrieve certain records from that join table, based on dynamic information. You can make a custom method in the serializer, and grab the relevant records via the dynamic information you pass in via instance options. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>A Quick Intro to Using the FireBase key on a custom backend: Part One</title>
      <dc:creator>Jason M</dc:creator>
      <pubDate>Tue, 25 Feb 2020 18:11:24 +0000</pubDate>
      <link>https://dev.to/ingrey1/a-quick-intro-to-using-the-firebase-key-on-a-custom-backend-part-one-3ff1</link>
      <guid>https://dev.to/ingrey1/a-quick-intro-to-using-the-firebase-key-on-a-custom-backend-part-one-3ff1</guid>
      <description>&lt;p&gt;Firebase is an amazon suite of products aimed at supporting web and mobile applications. The services include various data storage options, as well as authentication services. Since authentication and authorization can be a pain, smaller teams / independent developers might very well want to ‘outsource’ their authentication to the firebase service, rather than handle it themselves.&lt;/p&gt;

&lt;p&gt;Firebase offers a javascript SDK that provides the ability authenticate via the tried and true email / password combo, or any one of the third-party supported auth providers (which can be configured in the firebase console). &lt;/p&gt;

&lt;p&gt;After using one of the built-in methods the client javascript SDK provides to send an authentication request to Google. &lt;br&gt;
 if the credentials are valid, the response the client receives back will include a “fire-token”. It will look something like this:&lt;/p&gt;

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

&lt;p&gt;For basic authentication, we're interested in the idToken in the credentials object. This fire-token is a JWT token, encrypted via the RS256 algorithm.&lt;/p&gt;

&lt;p&gt;If you have a custom backend you're going to want to save this token to local storage on the client side, and send it along with requests for resources on your backend that require authentication.&lt;/p&gt;

&lt;p&gt;After sending the fire token to the backend, you're going to want to decode it. There is SDK support for decoding the fire token for some languages. Unfortunately, if your backend is rails, you're going to have to do it yourself.&lt;/p&gt;

&lt;p&gt;The decoded token will look something like this:&lt;/p&gt;

&lt;p&gt;Header Info&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_sXICN1n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zam9xwhajuki04fpsvwj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_sXICN1n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zam9xwhajuki04fpsvwj.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Data Payload&lt;/p&gt;

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

&lt;p&gt;To verify the fire token, first decode it using a standard JWT library for your language. Then you will need to perform some validations. Taken directly from the firebase docs: &lt;/p&gt;

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

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

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

&lt;p&gt;In Part 2, I will go over each of these validations in more detail.&lt;/p&gt;

&lt;p&gt;Until Then.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A Few Thoughts About Authentication </title>
      <dc:creator>Jason M</dc:creator>
      <pubDate>Tue, 11 Feb 2020 21:28:59 +0000</pubDate>
      <link>https://dev.to/ingrey1/a-few-thoughts-about-authentication-27ae</link>
      <guid>https://dev.to/ingrey1/a-few-thoughts-about-authentication-27ae</guid>
      <description>&lt;p&gt;Most people would prefer to login via an existing service they use – for example, google, facebook, twitter etc. – rather than sign up for a new service. And often new potential users will not choose your service precisely because they don’t want to bother with the hassle of registering and keeping track of one more account, since you don’t offer an authentication option they currently use.&lt;/p&gt;

&lt;p&gt;Of course, if you have a truly unique service – something that none of your competitors provide – then you’re likely to be okay. But most apps have competitors, and providing third-party authentication login options might mean the difference between customers choosing to make use of your service or another service.&lt;/p&gt;

&lt;p&gt;The upshot is that you should always provide login options via federated companies like Google and Facebook. However, as an independent developer, or a developer on a small team, there are many options related to the implementation of third-party authentication.&lt;/p&gt;

&lt;p&gt;We can divide the potential options into three broad categories (1) build from scratch (2) use an authentication library / framework, (3) use an authentication service.&lt;/p&gt;

&lt;p&gt;(1) certainly offers the most flexibility and freedom with respect to design and implementation at every stage of the authentication flow, but it’s probably not a feasible option for a lone developer or a small team – as they say, there’s no need to re-invent the wheel.&lt;/p&gt;

&lt;p&gt;(2) Can be a good choice. There are a number of authentication libraries (e.g., passport for Express, Devise for Rails) that are built to flexibly incorporate new login ‘strategies’. For example, you could build a strategy that makes use of the Facebook login API so that users can authenticate and sign up for your application via the OAuth protocol. If your application uses only one or two strategies, then this may be a solid choice. However, the more strategies incorporated into your application, the greater the time needed for both setup and maintenance. &lt;/p&gt;

&lt;p&gt;After all, sometimes authentication and authorization APIs change, or become deprecated for certain services like Facebook login. This means you may very well have to go back and make changes to the strategy that dealt with that API.   &lt;/p&gt;

&lt;p&gt;(3), authentication as a service, delegates or outsources the bulk of authentication and authorization code to a third-party. Firebase Authentication is a popular option in this category. Firebase will provide secure login via password / username, popular federated providers (facebook, google, twitter etc), or by phone number / email. Firebase Authentication also handles password retrieval via email and phone text. &lt;br&gt;
   To make use of Firebase Authentication in a full-stack application requires implementing a javascript Firebase UI component, which handles all of the business logic associated with the user logging in. The user will receive a firebase key. This key needs to go in the headers of any requests to your backend the user’s actions generate. On the backend, the token can be decoded either by (1) using Firebase’s sdk for your language, or (in case your backend isn’t supported), (2)  make use of one of the many jwt libraries to extract the relevant information.&lt;/p&gt;

&lt;p&gt;Firebase may be the best choice for small teams and independent developers because it allows them to focus on development the meat of their application, rather than dealing with the hassle of authentication. &lt;/p&gt;

&lt;p&gt;However, there are potential dangers associated with using full-featured services like this. If the service shuts down or changes it’s feature-set in an undesirable way, you will have no control over it, and may have to go back to the drawing board and adopt a different authentication solution.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A Beginner's guide to examining .CSV data in R Studio</title>
      <dc:creator>Jason M</dc:creator>
      <pubDate>Tue, 21 Jan 2020 06:26:19 +0000</pubDate>
      <link>https://dev.to/ingrey1/a-beginner-s-guide-to-examining-csv-data-in-r-studio-1n9g</link>
      <guid>https://dev.to/ingrey1/a-beginner-s-guide-to-examining-csv-data-in-r-studio-1n9g</guid>
      <description>&lt;p&gt;These days, there are tons of options available for exploring datasets. One of my favorite environments is R Studio. It's free, open-source, and powerful. R Studio is an IDE for R, a popular veteran programming language, tailored toward data analysis and display. R has thousands of packages which are particularly useful for data analysis, with specialized functions for a variety of scientific disciplines.&lt;/p&gt;

&lt;p&gt;In this article, we will learn how to convert a .csv file into a data frame in R Studio, and explore the data via the data frame's built-in capabilities. &lt;/p&gt;

&lt;p&gt;Go ahead and download and install the latest version of R for your operating system, and then install R Studio.&lt;/p&gt;

&lt;p&gt;Now that you have R Studio installed, the first thing we're going to do is install a handy general purpose library for manipulating data in R.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight r"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;install.packages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"dplyr"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

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



&lt;p&gt;We will need some sample data in .csv form. You can use whatever .csv file happens to be hand (there are plenty available for free on the internet). I grabbed a .csv file with 10k records, see the link here: &lt;/p&gt;

&lt;p&gt;&lt;a href="http://eforexcel.com/wp/wp-content/uploads/2017/07/10000-Sales-Records.zip"&gt;http://eforexcel.com/wp/wp-content/uploads/2017/07/10000-Sales-Records.zip&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The basic ingredients are in play, now we need to load our .csv frame into R.&lt;/p&gt;

&lt;p&gt;First, check our R Studio working directory. In the R Studio console, type&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight r"&gt;&lt;code&gt;&lt;span class="n"&gt;getwd&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;My directory is documents, so I'm going to place my .csv file my documents folder. Then, I will go ahead and load that .csv file, and convert it into a native R data frame.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight r"&gt;&lt;code&gt;&lt;span class="n"&gt;my_records&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;csv.read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"my_records"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;  
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, my data is living in a data frame. This means that I get access to a lot of handy methods.&lt;/p&gt;

&lt;p&gt;To view the number of rows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight r"&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nrow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_records&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To view the number of columns&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight r"&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ncol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_records&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To view the column names&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight r"&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;colnames&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_records&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To view the first 10 rows of data&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight r"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_records&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To view the last 10 rows of data&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight r"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_records&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To get the sum of the values in a column, by column name&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight r"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_records&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Total.Profit'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Sample 5 random rows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight r"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;dplyr&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;sample_n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_records&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Filter data frame by column values, where Total Cost is greater than 1000&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight r"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;dplyr&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_records&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Total.Cost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Remove Duplicate Rows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight r"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;dplyr&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;distinct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_records&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Select top 5 records, sorted by Total.Cost&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight r"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;dplyr&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;top_n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_records&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Total.Cost&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Average of Total.Cost&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight r"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;dplyr&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;summarise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_records&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Total.Profit&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Min value in column Total.Cost&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight r"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;dplyr&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;summarise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_records&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Total.Profit&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Max value in column Total.Cost&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight r"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;dplyr&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;summarise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_records&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Total.Profit&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Ensuring Immutability in Redux Reducers: Tips for Beginners</title>
      <dc:creator>Jason M</dc:creator>
      <pubDate>Mon, 30 Dec 2019 17:02:40 +0000</pubDate>
      <link>https://dev.to/ingrey1/ensuring-immutability-in-redux-reducers-tips-for-beginners-3ecm</link>
      <guid>https://dev.to/ingrey1/ensuring-immutability-in-redux-reducers-tips-for-beginners-3ecm</guid>
      <description>&lt;p&gt;The front-end for web applications has become increasingly complex, and each year there seem to be more sophisticated data structures, more variables, and more dependencies. While this complexity provides a richer user experience, it can lead to a headache in terms of maintenance and debugging for developers.&lt;/p&gt;

&lt;p&gt;Fortunately, along with the difficulties increased complexity has brought us, we've been given a few wonderful tools to deal with it. One of these tools is called Redux. Redux allows us to manage the data which underlies our web application's UI in an effective manner by (1) making sure that data lives in one location, and (2) enforcing a single process for updating that data.&lt;/p&gt;

&lt;p&gt;In Redux, the data lives in the store, a plain javascript object that can take many forms, depending on the different kinds of data your application uses. Here's a simple example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;authors&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="s2"&gt;Robert Jordan&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;books&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;16&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;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="s2"&gt;Stephen King&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;books&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2&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;span class="na"&gt;books&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="s2"&gt;the eye of the world&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;16&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;authors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&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;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="s2"&gt;the shining&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;authors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;6&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;span class="p"&gt;};&lt;/span&gt;    

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



&lt;p&gt;In the above example, the store has two kinds of data for the application, books and authors. In the Redux system, each of these pieces of data will have a separate Reducer function which is responsible for handling updates for that piece of data. The reducer for books might look a little bit 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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ADD_BOOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DELETE_BOOK&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../actions/index.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;booksReducer&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="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;ADD_BOOK&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="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="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;DELETE_BOOK&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="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;book&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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="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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;booksReducer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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



&lt;p&gt;Any update that is going to happen to the books array in the store will be done through this booksReducer function. This reducer takes the existing state (in this case, the books array), and a redux action object as arguments. The action object 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="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="nx"&gt;ADD_BOOK&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="nl"&gt;id&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Robin Hobb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="nx"&gt;books&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;456&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="s2"&gt;27&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt;   
&lt;span class="p"&gt;}&lt;/span&gt;

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



&lt;p&gt;The action object tells the reducer function what sort of thing to do with the accompanying payload information. So, this action will be used to update the store with the new book, in the switch statement for the ADD_BOOK case.&lt;/p&gt;

&lt;p&gt;However, whatever action happens to be passed to a reducer function, it's incredibly important that any work done inside the function does not mutate the original state, but instead returns a new altered copy of the data. Violating this principle could very well lead you down a horrible rabbit hole of debugging.&lt;/p&gt;

&lt;p&gt;But there are a number of options available to decrease or eliminate the likelihood of accidentally causing mutations in your data inside your reducer functions.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;For each of your reducers, for each case or possibility, write a test to make sure no mutations have occurred. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The easiest way to structure this test is just to use a deep-copy library, to copy your state before applying the reducer function to the original state. Then, call the reducer function, and using deep comparison testing (which most test frameworks, such as mocha, will have), make sure the returned state is deeply equal to the original state.&lt;/p&gt;

&lt;p&gt;Using some simple tests in this way, you can find out if any of your reducer functions are slipping some unexpected mutations.  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Deep-copy your state inside the reducer function before doing any work on it. Then return the altered copy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use a library like Immer or Immutable that has custom, immutable objects which don't let you mutate state.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Option 1 is always a good idea, since it can never hurt to have a few more tests, and the time writing the tests could very well save you a lot more time debugging code in the future. Option 2 will ensure that no mutation occurs, but straight up deep copying before doing any work in the reducer is wasteful from a performance perspective, so should be avoided on larger projects. &lt;/p&gt;

&lt;p&gt;Option 3 will ensure immutability, but it will also require you to learn another library, and introduce another dependency into your project. Some of these libraries are easier to work with than others, so if you're going to take this route, I suggest reading up the tradeoffs between the popular immutable libraries like Immer and Immutable.            &lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
