Using Maybes with React-Redux

Moving the handling of undefined to the edges of the stack

Dan Hood
AnyJunk
5 min readFeb 16, 2018

--

Maybe combination using flatMap

A pervasive problem with many languages, but particularly with JavaScript, is undefined. You have to consistently check whether something exists every time you interact with it otherwise you will get errors. Flow, and other typing systems, make this a little easier by reminding you that something might be undefined. But you still have to apply the checks everywhere. This is where some functional languages, like Scala or Haskell, make use of something called a Maybe. And at AnyJunk we apply that same philosophy to the front end.

First I will explain some features of the Maybe and how it operates. If you have come across, or used, Maybes before then this next section might be of less interest to you, but I encourage you to read on for the later parts where I will introduce it into React-Redux.

A Maybe is a construct that can wrap around a potentially undefined value and help you interact with it in a smooth and predictable manner. It also convey some other benefits but I will get onto that later.

A Maybe has two sub-types: None, and Some. I find the easiest way to think of these are like an empty list, and a list containing a single element respectively:

  • None =[]
  • Some(x) = [x]

Importantly, the empty list still has all the same methods as the list that contains an element, but most of them will not actually change it.

The starting point is usually some helper method that will construct a Maybe from another type that may be null. In our web app we use monet which has a Maybe.fromNull method that accepts a value that might be null or undefined; it returns:

  • None if value is undefined or null
  • Some(value) if value is defined.

(In our mobile app we instead use folktale that has a similar method: Maybe.fromNullable.)

In order to carry out an operation on the value inside a Maybe you can call .map on it, the same way you would to change a value inside a list. If you had a value this will change it, if you didn’t have a value everything still works but nothing changes.

When you want to actually display the value you will need to deconstruct the Maybe and get the value out if you have it. If you don’t have a value you’ll need to provide some sort of alternative. In monet the method for this is called orSome. To use it you would do something of the form: maybeNumber.orSome(0)

These three methods (fromNull, map, orSome) come together to mean that you construct a Maybe at one edge of your stack and resolve it at the other edge, passing it through as a Maybe and using .map on it in the intermediate parts. This can mean taking a value that your API may or may not provide and using Maybe.fromNull to wrap it up, passing it through to your component and then calling .orSome to decide what to display as an alternative if you don’t have it. This could still be .orSome(null) but, importantly, you only have to decide that right at the end, nothing before then needs to know what the alternative is.

One more thing that Maybes give you that is very helpful is a flatMap (aka chain in folktale). This acts like map but allows you to combine two Maybes and it returns None if either of them are None and Some only if they are both Some. For instance:

If you wanted to extend this to more values that may or may not exist you just include more flatMaps.

If you are familiar with flow’s notation for types the types of these are as follows:

There are further constructs that can help with all that nesting, but I will leave that for a future post as I don’t want to overly complicate matters here.

Now that we’ve discussed a bit about Maybes and how they work we need to decide where we put them in our structure. At this point I would encourage anyone who has not already done so to read my previous post about structuring react and redux since I will be using some terms that I introduced there and it may help to know exactly what I mean by them.

If you use immutable for your redux state then you know that when you use get or getIn you can’t rely on getting the value you expect, even with flow to help you. We have a helper for that called safeGet which is like getIn except it returns a Maybe containing the value.

If you have a fully typed redux state then you can store objects in it as Maybes directly. This is particularly helpful for data that needs to be loaded in by an asynchronous call to the API. Indeed, on your first load of a component the data will not be there so your lens will not be able to return it. This means that the lenses that we introduced in the last post should in fact all return Maybes.

The getter part of the lens will use safeGet to give you a Maybe of an immutable object and then you use map to apply the marshaller to that object and get a Maybe of your view model.

If you have a normalised state there are several different objects that could fail to be present and any one of them means that you can’t build your view model. This is where flatMap can help you.

Of course if the address here is optional then just use map instead of flatMap.

The Form decides how to handle the None case, depending on the use case:

  • display a message telling the user that no data could be found,
  • or load up some defaults for creating a new entry

Additionally there are certain parts of your model that may be optional and a Maybe might help you handle those, especially if you have a derived field that depends on several optional fields like in the above example (of a full name that depends on a first name and a last name).

In simple cases where it’s just an optional string you might want to handle it in the view model itself and resolve it to a default like ‘-’ if it’s not there. In more complex cases where an entire section of the form is irrelevant if a piece of information is not present then you can have the Maybe be part of your view model and resolve it in the component.

However it is dealt with you always need to use orSome as the final thing you do with your Maybe. Maybes usually work best when you avoid using orSome for as long as possible.

So now we’ve seen how we get a Maybe out of the state, let it pass undisturbed through the lens and marshaller and then resolve it in the Form. We’ve also seen how we can combine Maybes to form a single Maybe. Hopefully you have thought of some places in your code that could be simplified by using Maybes.

In the next post I discuss a helper function that we use at AnyJunk to simplify the combining of multiple Maybes. Hopefully that will address any reservations you have about the complexity, level of indentation and number of brackets involved in the process.

--

--