Elm's Remote Data Type in Javascript

Elm's Remote Data Type in Javascript

Elm's Remote Data Type in Javascript - Often in web development there is this recurring pattern of having to fetch some data from some server through a rest api, and then show it someway in the UI.

Originally published by Jason  at dev.to

This often includes storing this data somewhere on the client side, either in a store or just a variable you can reference, and this is where the Remote Data type can help.

Usually saving the data would look something like this in JS:

// Javascript

const state = { data: null, error: null }

fetch('/api/data') .then(res => res.json()) .then(data => state.data = data) .catch(err => state.error = err)

and showing it on screen:

// React

const MyComp = ({ error, data }) => { if (error) { return <div className="error">{error}</div> } else { return <div>{data}</div> } }

But there are a few problems with this approach:

  1. What do we show on screen when the data is loading from the server?
  2. What do we show on screen before we even request the data from the server?
  3. Do we properly clear the previous error if the data is a success?
  4. Do we properly clear the previous data if we get an error?

So how can we solve this?

Some might recommend we can add more fields to our state to help represent all the cases, like this:

// Javascript

const state = { data: null, error: null, loading: false, isAsked: false }

and in the UI would be similar to this:

// React

const MyComp = ({ error, data, loading, isAsked }) => { if (!isAsked) { return <div>Nothing asked yet</div> }

if (loading) { return <div>Loading...</div> }

if (error) { return <div className="error">{error}</div> }

if (data) { return <div>{data}</div> }

return <div>Some default fallback to be safe</div> }

But the problem with this is that it becomes too easy for our UI to accidently show the wrong case by forgetting to set loading to false after the data comes back as an error, or forgetting to clear the error if a retry returned a success.

Infact, optimistically the structure above can have a cardinality of 2 x 2 x 2 x 2 which is 16 possible different combinations of states we can be in at any given time. That is a lot of cases to represent.

Let's look at how Elm simplifies this process with needing only 4 cases.

Remote Data in Elm

The Remote Data type can be created manually by writing a custom type like below, or by using a pre-made version from a library like krisajenkins/remotedata:

-- Elm

type RemoteData e a = NotAsked | Loading | Error e | Success a

and then using this type as your model:

-- Elm

type alias Model = RemoteData String MyData

-- and set the initial model value as NotAsked

init = NotAsked

What we need to understand is that our state can only be one of these 4 types at any time. We can not both be in a Loading state and in a Success state at the same time, or else our UI will be showing 2 different things. This is why our cardinality is only 4 now instead of 16, because there is no way to represent our state more than that.

Using this model we can now create a UI for each case like this:

-- Elm

view model = case model of NotAsked -> div [] [ text "Not asked yet" ]

Loading -&gt; div [] [ text "Loading..." ]

Error err -&gt; div [] [ text err ]

Success data -&gt; div [] [ text &lt;| "Here is my data: " ++ data ]

And now whenever we update our state, we never need to worry about clearing previous state or forgetting to flip one field to null - because there is only one field in our model.

This is a great pattern for handling remote data fetching in Elm, but how do we take advantage of this pattern in Javascript? Daggy.


There are a few different libraries in Javascript that can help model your application with Algebraic Data Types like we have in Elm with the typekeyword. One popular library is Daggy.

To represent remote data in Daggy, we would create a type like this:

// Javascript

import { taggedSum } from 'daggy'

const RemoteData = taggedSum('RemoteData', { NotAsked: [], Loading: [], Error: ['e'], Success: ['a'] })

Then once we have our type, the implementation is almost identical to how we would work in Elm.

Our state would only have one field instead of 4, and a cardinality of 4 instead of 16.

// Javascript

const state = { data: RemoteData.NotAsked }

// Fetch some data

state.data = RemoteData.Loading

fetch('/api/data') .then(res => res.json()) .then(data => state.data = RemoteData.Success(data)) .catch(err => state.data = RemoteData.Error(err))

And in our UI, like React, we would have:

// React

const MyComp = ({ data}) => data.cata({ NotAsked: () => <div>Not asked yet</div>, Loading: () => <div>Loading...</div>, Error: err => <div>{err}</div>, Success: d => <div>Here is my data: {d}</div> })

Using this pattern actually helps move a lot of render logic out of your components in React, like checking fields with if (field) {...} and instead moves that responsibility to something like a reducer, which will make it a lot easier to run unit tests on.

If you would like to learn more about Algebraic Data Types in Javascript, check out these links:

Originally published by Jason  at dev.to


Thanks for reading :heart: If you liked this post, share it with all of your programming buddies! Follow me on Facebook | Twitter

Learn More

☞ Svelte.js - The Complete Guide

☞ The Complete JavaScript Course 2019: Build Real Projects!

☞ Become a JavaScript developer - Learn (React, Node,Angular)

☞ JavaScript: Understanding the Weird Parts

☞ JavaScript: Coding Challenges Bootcamp - 2019

☞ The Complete Node.js Developer Course (3rd Edition)

☞ Angular & NodeJS - The MEAN Stack Guide

☞ NodeJS - The Complete Guide (incl. MVC, REST APIs, GraphQL)

☞ Node.js Absolute Beginners Guide - Learn Node From Scratch

javascript web-development

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Hire Web Developer

Looking for an attractive & user-friendly web developer? HourlyDeveloper.io, a leading web, and mobile app development company, offers web developers for hire through flexible engagement models. You can **[Hire Web...

Why Web Development is Important for your Business

With the rapid development in technology, the old ways to do business have changed completely. A lot more advanced and developed ways are ...

Important Reasons to Hire a Professional Web Development Company

    You name the business and I will tell you how web development can help you promote your business. If it is a startup or you seeking some...

Hire Dedicated eCommerce Web Developers | Top eCommerce Web Designers

Build your eCommerce project by hiring our expert eCommerce Website developers. Our Dedicated Web Designers develop powerful & robust website in a short span of time.

How long does it take to develop/build an app?

This article covers A-Z about the mobile and web app development process and answers your question on how long does it take to develop/build an app.