Achieve more with Less code, Elm vs React-Redux-Flow

August 20, 2018 0 Comments

Achieve more with Less code, Elm vs React-Redux-Flow

 

 

Elm Language was specifically designed to build front-end applications, and it offers a great experience as a whole. Its most shiny features are:

  1. Great performance using the virtual DOM
  2. Functional language
  3. Safety through a Powerful type system
  4. State management using the built-in Elm architecture
  5. A powerful and helpful compiler

We will see how to achieve 3, 4 and 5 using React, Redux and Flow.

Let's look at some Elm code:

import Html exposing (Html, button, div, text)  
import Html.Events exposing (onClick) main = Html.beginnerProgram { model = model , view = view , update = update } -- MODEL  
type alias Model = Int model : Model  
model = 0 -- UPDATE  
type Msg = Increment | Decrement update : Msg -> Model -> Model  
update msg model = case msg of Increment -> model + 1 Decrement -> model - 1 -- VIEW  
view : Model -> Html Msg  
view model = div [] [ button [ onClick Decrement ] [ text "-" ] , div [] [ text (toString model) ] , button [ onClick Increment ] [ text "+" ] ]

https://gist.github.com/haikyuu/abd1145667e02aee2332d55e0d99bd33

The beauty of Elm is that every Elm app is written using the same parts:

  • Model: what is the state of your app

  • Update: how to update the state

  • View: how to display the state

The syntax is a bit weird for newcomers but it just takes some getting used to.

And its equivalent (commented) using React, Redux and Flow:

//@flow  
import React from 'react';  
import ReactDOM from 'react-dom';  
import { createStore, bindActionCreators } from 'redux'  
import { Provider, connect } from 'react-redux' type Increment = { type: "INCREMENT"  
}
type Decrement = { type: "DECREMENT"  
}
type CounterActions = | Increment | Decrement type Action = CounterActions // whenever we add a reducer, we add its actions here //make sure dispatch can only dispatch our predefined actions  
//and returns the action dispatched
type domainIdentity<T> = <A: T>(a: A) => A  
type Dispatch = domainIdentity<Action> type CounterState = number //reducer  
const counter = (state: CounterState = 0, action: CounterActions) =>{ switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 default: (action: empty); //to make sure we handle all the actions //it will trigger a flow error when we forget a case !! return state }  
} //action creators
const increment = (): Increment => ({ type: "INCREMENT" })  
const decrement = (): Decrement => ({ type: "DECREMENT" }) // our global state, also needs to be modified whenever we add a reducer  
type State = CounterState // passing state to our component as props  
const mapStateToProps = (state: State) => ({state}) const mapDispatchToProps = (dispatch: Dispatch) => bindActionCreators({ increment, decrement,  
}, dispatch) //helper flow types .. should be in a config file
type _ExtractReturn<B, F: (...args: any[]) => B> = B;  
/*export*/ type ExtractReturn<F> = _ExtractReturn<*, F>; //redux state and action creators types
type ReduxProps = ExtractReturn<typeof mapStateToProps>;  
type ReduxActions = ExtractReturn<typeof mapDispatchToProps>; //View  
//we don't have any props except redux ones
type Props = {} & ReduxProps & ReduxActions  
const App = ({ decrement, increment, state }: Props) =>( <div> <button onClick={decrement}>-</button> <div>{state}</div> <button onClick={increment}>+</button> </div>  
)
//connect our component with the redux store
const ConnectedApp = connect(mapStateToProps, mapDispatchToProps)(App) let store = createStore(counter) ReactDOM.render( (<Provider store={store}> <ConnectedApp /> </Provider>), document.getElementById('root')  
);

https://gist.github.com/haikyuu/a540268b3336a52de69ae94d8e3b9e3c

A few things to note:

  • Elm’s type system is much more powerful and descriptive than Flow (and typescript)

  • The Elm architecture is integrated in the language level, so you can achieve more with less code in Elm compared to how much boilerplate you need to write in Redux.

  • Redux was inspired from Elm architecture

If you cannot use Elm in your day job, you can still benefit from similar goodies using Flow.

You will also become a better React developer by learning Elm, so check it out.

React and React Native developer. Loves Flow and currently exploring OCaml and ReasonML. Curious and eager to learn.


Tag cloud