Mark's Dev Links - Issue #1

This is a post in the Newsletter series.


Weekly newsletter, sent week of 2018-01-22

Hi, and welcome to the inaugural issue of Mark's Dev Links! This is hopefully going to be a weekly-ish email newsletter, focused on the React and Redux ecosystem.

Since it's the first issue, I'm still trying to figure out exactly where I want to go with this. The whole idea was kind of spur-of-the-moment yesterday. I blame Gosha Arinich, who's been poking me to try out a mailing list for a while,and of course Kent C Dodds's newsletter is an inspiration as well.

I'm generally picturing a format along these lines:

  • A few selected articles and discussions of interest, with the articles probably drawn from updates to my React/Redux links list
  • One or more highlighted Redux-related addons or libraries, similarly drawn from updates to my Redux addons catalog
  • Possibly a spotlight on an open Redux issue, or status of the library
  • Any new articles or updates I've posted to my own blog
  • Quick recap of what I'm up to and what I've been working on

The archived newsletters will be available at https://tinyletter.com/acemarke , assuming I've set this up right. I'm also still debating whether or not to post them on my blog.

Note: Since you're seeing this, I did indeed decide to post this on my blog, on a one-week delay.

Definitely open to feedback and suggestions for stuff you'd like to see in these newsletters.

So with that in mind, let's get to it!

React Lifecycle Changes and Async Behavior 🔗︎

The React team has been broadly hinting that the upcoming async rendering behavior is going to lead to major changes in how React works, and that the changes will impact the entire React ecosystem. That's moving forward, as the RFC for new async-safe lifecycle methods has been merged in. All the componentWill* methods will be renamed to UNSAFE_componentWill*, and a new static getDerivedStateFromProps method will be added as a replacement. Expect more changes to come.

Webpack 4 Alpha 🔗︎

Tobias Koppers has been cranking out work on Webpack v4. It will include "zero-config" default behavior out of the box, drop the old CommonsChunkPlugin in favor of a new chunking/code-splitting approach, and a lot more.

Redux Saga Testing 🔗︎

Looks at several ways to approach testing sagas, and how specific saga test helper libraries use those approaches. Includes a helpful table listing which approaches each helper library supports.

Redux Ecosystem 🔗︎

Immer: Immutability through Mutability 🔗︎

One of the major pain points with Redux has been the need to update data immutably, which becomes more difficult when working with nested data. There's many existing immutable update utility libs, most of which take string key paths to indicate what part of a nested data structure to update.

Michel Westrate, author of MobX, has released a new library called Immer. It uses ES6 proxies to let you write normal mutative code within a callback, and tracks all of the changes you're making. It then applies those changes as proper immutable updates to safely generate the new state. As an example, this code is perfectly correct for use in a Redux reducer:

import produce from "immer";

// later
const nextTodos = produce(todos, draft => {
    draft.push({ text: "learn immer", done: true })
    draft[1].done = true
})

I haven't had a chance to use it yet myself, but it appears to be a great solution for updating state immutably. Should be good for use in Redux reducers, React components, or anywhere else you need to do immutable updates.

Redux Issues Spotlight 🔗︎

Redux 4.0 Beta ! 🔗︎

Tim Dorr has put out Redux 4.0.0 beta 1. It's primarily cleanup around the edges - updated TypeScript typings, dropping Lodash's _.isPlainObject for a homegrown version that's faster, and various other mostly internal fixes. Try it out and let us know if you find any problems.

Me, Myself, and I 🔗︎

(I'll hopefully figure out a better name for this section eventually. This is what you get for signing up for the first issue :) )

My schedule for the next few months is starting to fill up a bit. I've agreed to give my "Intro to React and Redux" presentation at a couple of local meetups in March and May. I just submitted a conference proposal for the near future, and we'll see how that pans out. Finally, I'm hoping to start teaching some Redux workshops later this year, and I'm bookmarking everything Kent C Dodds has ever written on the topic :) I actually asked Kent a question about planning for workshops on his AMA repo, and he was kind enough to write a very detailed answer.

Experiments with Randomness in Redux 🔗︎

Someday, if I actually have free time, I've got an old side project I'd like to reimplement. It's a board game that has dice rolling in it, and that means randomness.

Now, random numbers in Redux are tricky, because the randomness needs to live outside reducers in order for them to actually be "pure". At a minimum, we want the exact same output for the exact same (state, action) input. In theory, there shouldn't be any effects on the outside world at all, either.

There's two good articles on randomness in Redux that I've seen: Roll the Dice: Random Numbers in Redux and Random in Redux. However, what neither of these gives us is an easy way to generate an arbitrary amount of random numbers in a single dispatch, repeatably.

Yesterday I was playing around with the idea of a Redux middleware that would store a random number generator instance that could have its internal state saved and updated, and I seem to have gotten something working. I've put the whole code in a gist at https://gist.github.com/markerikson/9951faf2fa8f04f9a197784d47ee9ad3 , but here's the highlights:

import seedrandom from "seedrandom";

export const randomMiddleware = store => {
    let prng = seedrandom(null, {state : true});

    return next => action => {

        const {meta = {}} = action;

        const rngState = prng.state();

        const newMeta = {...meta, rngState};
        const newAction = {...action, meta : newMeta};

        const result = next(newAction);

        const newRngState = newAction.meta.rngState || rngState;
        prng = seedrandom(null, {state : newRngState});

        return action;
    }
}

function higherOrderRandomReducer(reducer) {
    return function (state, action) {
        if(action.meta && action.meta.rngState) {
            action.meta.prng = seedrandom(null, {state : action.meta.rngState});
        }

        const actualResult = reducer(state, action);

        if(action.meta && action.meta.prng) {
            const rngState = action.meta.prng.state();
            action.meta.rngState = rngState;
        }

        return actualResult;
    }
}

The trick here is that whenever an action is dispatched, the middleware serializes the PRNG's internal state and adds it to the meta field in the action. When the action reaches the reducers, the higher-order reducer instantiates a new copy of the PRNG, and uses the serialized state to initialize it. When the reducer returns, we serialize this second PRNG instance's state, and overwrite the state value in the action. When the action gets back to the middleware, it can then update/re-create its own PRNG instance with that state.

It's fragile, it's unoptimized, and it's admittedly a really indirect way of going about handling random numbers. (You can also argue that having the reducer modify the action with the updated PRNG state makes it "impure", and you'd have a good case.) But, I think it's interesting and useful enough to flesh out, and it does actually (mostly) fulfill the desire to let a reducer generate as many random numbers as it wants based just on the contents of the action. If you try out the part of the gist where I dispatch multiple "INCREMENT" actions and then re-apply the saved PRNG state, you can see it repeatably generates the same numbers each time. This would also be useful for testing purposes.

Wrapping Up 🔗︎

So, there you have it for issue #1. Can't guarantee they'll all be this long, or that they'll come out on exactly a weekly schedule, but hopefully I'll be able to put them out on a consistent basis. As I said earlier, I'd love to hear feedback and suggestions for what you'd like to see.

(Also, I apparently don't know how to write anything "short".)

Obligatory Plug 🔗︎

My "Practical Redux" tutorial series is now an interactive course on Educative.io!. Right now, Educative is having a sale - all courses are 50% off with coupon code LEARN2018 . That includes not just my "Practical Redux" course, but many others as well. Check it out!


This is a post in the Newsletter series. Other posts in this series: