The Redux Pattern As a First-Class Citizen
(A Redux Developer’s Guide to Elm Basics)
Why Look at Elm?
Unlike Redux, Elm is a language, so it is able to benefit from many things like enforced purity, static typing, out of the box immutability, and pattern matching (using the case expression). Even if you don’t plan to use Elm, you should read about the Elm architecture, and play with it.
— From the Official Redux Guide Prior Art section
If You Know Redux, You Know The Elm Architecture!
The words in parens are the Redux equivalents of the Elm concept they are next to. This article describes these differences in more detail and compares the equivalent code in both.
If They’re The Same, Why Consider Elm?
There have been a lot of articles recently about moving away from Redux. The consensus seems to be that the Redux Pattern can make code more maintainable and reduce data synchronization bugs, but the cost is too high because it requires so much boilerplate. So many people are recommending using the same patterns without the Redux library itself (including Dan Abramov, the original author of Redux; see this post as well).
But there’s another option! With Elm, the patterns of Redux are built into the language itself (not an optional library or framework). That means that it’s a lot more natural because the language is literally built for creating apps using that pattern. It also means no “JavaScript Fatigue” because Elm is opinionated about its data store. So no updating to the flavor-of-the-month data store (and a custom set of supporting libraries). Plus, you have to deal with a lot less boilerplate, and you have the famously helpful Elm compiler helping you avoid bugs!
Comparing Elm and Redux
This guide is meant to bridge the gap and help you learn Elm by leveraging the knowledge you already have about Redux. We’ll compare basic Counter apps in both paradigms. This isn’t meant to be a comprehensive comparison, but rather a basic intro to the fundamentals.
Here are the full code examples used throughout this guide:
⚛ Live Example in Redux
🌳 Live Example in Elm
(The Redux example is in a single file for easy comparison; see this codesandbox for the same example split into multiple files).
Initializing and Updating State
⚛ Redux Reducers, 🌳 Elm update
and init
functions
⚛ Redux Reducer
🌳 Elm update
/init
functions
Notice that we have to have a default case in Redux. Since action.type
is just a string it could be anything. Often tools like TypeScript or Flow are used to help make sure we are handling each valid case and don’t have any typos or incorrect assumptions about the Redux event payloads.
Using just Vanilla Elm, the compiler gives you these guarantees. And there are no escape hatches like TypeScript’s any
type, so if your program runs you are guaranteed that there will be no unhandled cases or runtime exceptions.
Triggering Events
⚛ Redux Actions, 🌳 Elm Messages (Msg
)
⚛ Redux Actions
🌳 Elm Messages (Msg
)
Notice that in Elm, there is no wiring to manually dispatch
actions as there is in Redux. In React, onClick
takes a function, so you manually wire it up to call store.dispatch(...)
in the function you pass to onClick
. Elm assumes an architecture where you the only thing you can do from an onClick
(or any other event) is dispatch an action
(or Msg
in Elm lingo). So this is simpler and less error prone in Elm. You just declaratively give an onClick Increment
and The Elm Architecture takes care of the wiring to dispatch the Increment
Msg
at the appropriate time. This is one of the big benefits of having the data architecture built into the language. It’s also type-safe, which you’ll appreciate a lot more when you’re working with a large scale app and not just a toy example like this! That guarantees that every Msg
has exactly the data you said it would, and that you have handled every possible Msg
(and only possible Msg
s).
Also notice that there is no need for anything like PropTypes
in Elm to give you warnings when you forget to pass fields or pass in the wrong data type. This is built with Elm’s famously helpful compiler and type system!
HTML Templating
⚛ Redux JSX, 🌳 Elm Functions from the Html
Module
That’s right, Elm doesn’t have JSX
or a special templating syntax. It’s just plain-old Elm functions! This is one of those features that bothers people when they first use Elm, and then they fall in love with it after a few weeks! And as for the commas at the start of each line, you’ll get used to that, too. Especially because you don’t have to do it manually, elm-format
does it for you whenever you save your code!
Tooling
Built-In to Elm
People blame Redux, React, functional programming, immutability, and many other things for their woes, and I understand them.
— Dan Abramov (author of Redux), from You Might Not Need Redux
Indeed, introducing tools for immutability, or ensuring pure reducers is tedious in a React application. But these things aren’t inherently tedious. They are tedious because they are second-class citizens in JavaScript/React. In Elm, however, they are built-in and therefore require no special libraries, no linters or unit tests to ensure that you have pure functions. That’s just how Elm is, and it is very natural to work that way in that context.
Have questions? Drop me a line, or sign up for my Elm for Redux Devs series!
Want to learn my 3 favorite things about Elm? Sign up for my Elm For Redux Devs mini-course below. You’ll get an email in your inbox that gives you some resources about libraries and features of the Elm language to look forward to!
Trying Elm
Is your team curious about Elm? I train teams on Elm, and coach them through the transition from Redux to Elm to make sure it is smooth and successful. Say hello, or take a look at the free Elm intro sessions that we offer.
Thanks For Reading!
- What have been your stumbling blocks learning Elm?
- What do you love about what you’ve seen in Elm?
👇 Let me know in the comments below 👇
Did you know? 💡 If you learned something from this guide, you can give up to 50 claps! 👏