Functional Programming and React

  • Daniel Pedroso
  • February 25, 2019

React ❤️ Functional Programming

React is a framework that represents the multi-paradigm nature of JavaScript. You’ll find OOP (your class components inherit from Component or PureComponent), Prototype-based programming (after all, the class keyword is ultimately just syntactic sugar - it boils down to prototypes), and lots of love for Functional Programming (which is one of my passions).

Sadly though, a massive number of devs go through years of React without ever realising the FP gems around them. If you’re experienced with React but have little exposure/understanding of Functional Programming, this post is for you. Who knows, you might even join me when I get my new tattoo (I’ve been planning on tattooing the Y combinator - seriously).

I’m ashamed to admit, but the first time I heard of Functional Programming, I immediately associated it with Pascal and old-school C. I made the very common mistake of mixing Procedural and Functional programming in the same bag.
The truth is, all they have in common is the fact that they’re both programming paradigms. The most obvious difference between them is that Procedural code is imperative while Functional code is declarative.

Functional Programming has a ridiculous amount of theory behind it - a standard joke is that functional programming combines the power and flexibility of abstract mathematics with the intuitive clarity of abstract mathematics.

Wait, come back, don’t run away. Behind the “intellectual hipstery” there’s a lot of awesome, practical applications for functional programming - and your favourite front-end frameworks are full of them, just hiding in plain sight.

Some base concepts

So, in order to understand FP, there are a couple of concepts we need to understand first. The names for these concepts can sound intimidating, but they’re actually fairly simple.

Functions (or Pure Functions)

This is very obvious, but with a couple of twists. Functions here are representations of mathematical functions, which means:

  // This is a pure function
  const sum = (a, b) => a + b;

  // This is an impure function - returns a sum if AM, subtraction if PM
  const sumIfAM = (a, b) => {
    const time = new Date().getHours();
    if (time < 12) {
      return a + b;
    }

    return a - b;
  };

The impure function above was a ridiculous example, of course - but it’s depending on values that aren’t passed in as arguments, and won’t always return the same value given the same input.

Higher-Order Functions

Higher-order functions are functions that meet one of the following criteria:

Arity

Arity is just a fancy name for the number of arguments a function accepts.

Ok, where’s the React/Redux stuff???

Ok, let’s do it!

There are the obvious things - like the fact that within React you’re not supposed to mutate props, or state (you should call setState instead) and you’ve probably heard people in the React ecosystem talking extensively about pure functions and stuff.
Let’s look at some other stuff, starting from the most obvious ones:

Higher-Order Components

This one is self-explanatory - it’s very clearly an extension of the concept of Higher-Order Functions.
If, with a Higher-Order Function, you need to either take a function as argument or return a function, when dealing with HOCs you hit both targets.
You’re effectivelly creating a function that takes in a component, and returns another component that wraps the original argument.

  const withTitle = title => Component => (props) => (
    <div>
      <h1>{title}</h1>
      <Component {...props} />
    </div>
  );

  const MyComponentWithTitle = withTitle('Hi, Mom!')(MyComponent);

Other examples of HOCs:

Higher-Order Components are a fantastic way of creating reusable logic (this example obviously doesn’t do it a lot of justice).
I’ve recently found out about some companies (well, one company that I know of) that are considering HOCs an anti-pattern. Please don’t do that. How about understanding it instead? ;)

Redux-thunk

Redux-thunk is an interesting one - so many people use it, but almost no one understands why or what’s going on (which makes me sad 😢).
First off, let’s start with the name (if you’re anything like me, your first thought when you saw redux-thunk was “WHAT THE ACTUAL FRACK IS A THUNK???”).
Thunk is a function returned by a function. Example:

  function higherOrderFunction() {
    return function thunk() {
      return 'Hi, Mom!';
    };
  }

Yep, that’s all a thunk is. Well, it gets more complicated if you dive into the deep end of the pool, but let’s stay in the shallow side.

Here’s an example of a typical action creator that uses the thunk middleware:

  const fetchUser = userId => dispatch => axios.get(`/user/${userId}`)
    .then(({ data }) => dispatch(fetchUserSuccess(data)))
    .catch((err) => dispatch(fetchUserError(err)));

Beautiful. Now, why do we need it?

This is an interesting one - by default, Redux expects an object being dispatched. It works perfectly for synchronous action creators.
The problem starts to happen when you hit the real world. JavaScript is “single-threaded” (I’m using quotes here because this isn’t exactly accurate. I might write a post later about this topic), therefore almost everything in JS is asynchronous. You really don’t wanna block that event loop.
So, when you run dispatch(fetchUser(1)), you’re not dispatching an action object - you don’t really have the data at that point, and it won’t be available until your HTTP call resolves.
What redux-thunk does is:

  1. Create a middleware function
  2. Wait for new things to be dispatched
  3. Check the dispatched value - is it a function (a thunk)?
  4. If it is, call it passing dispatch and getState as arguments.
  5. If it isn’t, just let it go through the normal flow - it’s an actual action.

Now, we can nerd out a bit further here and analyse some of that behaviour (are you still with me? Good, I like you already!).

Currying and Partial Application

Currying and Partial Application are probably two of my favourite concepts ever.
Currying here has nothing to do with food - I love a good curry, so they have that in common - but with Haskell Curry, a huge name in combinatory logic.

With Currying, you’re taking a function of arity (number of arguments) n and turning it into n functions of arity 1. It’s easier to understand with an example, so here it goes:

  const sum = (a, b, c) => a + b + c;
  const curriedSum = a => b => c => a + b + c;

  console.log(sum(1, 2, 3)); // 6
  console.log(curriedSum(1)(2)(3)); // 6

Now, Partial Application is very similar, but not exactly the same thing. What you’re doing is fixing some of the arguments for your function. Example:

  const sum = (a, b) => a + b;
  const incrementBy = a => b => sum(a, b);

  const increment = incrementBy(1); // partially applied
  console.log(increment(1)) // 2
  console.log(increment(5)) // 6
  console.log(increment(100)) // 101

Now, with that in mind, let’s have a look at that action creator again and analyse the whole thing:
const fetchUser = userId => dispatch => ...
We can see straight away that, in this particular case, this is a curried function (it won’t always be, since curried functions require n functions of arity 1. Thunks here aren’t required to be unary functions, so this scenario was just serendipitous).

Furthermore, when we first call dispatch(fetchUser(1)) we’re using partial application - we’re fixing userId in that closure to the value 1.
Cool, so now the redux-thunk middleware will catch that thunk (the dispatch => ... part) and finally call it with the dispatch function. This thunk is, therefore, a Higher-Order Function (it’s receiving a function as an argument).
Once the promise resolves or rejects, it’ll finally dispatch one of two actions - and it can do that because dispatch is in the scope/closure of that function.

So much functional beauty ❤️ .

Redux’s Compose

Now, composition is another topic that’s absurdly cool, and one of the reasons why Functional Programming can be so damn powerful.
When you have a bunch of pure functions, you can start composing them together - meaning the result of one function can go straight as the argument for another function.
Example:

  const inc = a => a + 1;
  const square = a => a * a;
  const div2 = a => a / 2;

  // I want to increment a value, take the square, and then divide by 2.

  // without compose
  const process = val => div2(square(inc(val)));
  console.log(process(2)); // 4.5

  // with compose
  const composedProcess = compose(div2, square, inc);
  console.log(composedProcess(2)); // 4.5

What does that compose function look like, you may ask?

  const compose = (...fns) => val => fns.reduceRight((v, fn) => fn(v),  val);

Beautiful!

Final notes

This is already way bigger than I expected. We could keep going, but I need to draw a line here somewhere.
Let me know what your favourite FP concepts are - I didn’t really go into the Y combinator here, but it’s definitely my favourite! I might write a whole blog post about it someday :)