React.js: From basics to Redux

Agenda

  • UI components
  • Controlled components
  • DOM components
  • Logic components
  • Redux

Who am I?

  • Yehonathan Sharvit @viebel
  • A mathematician
  • A coder
  • A pragmatic theorist
  • A freak of interactivity
  • Founded Audyx in 2013 - an Audiology Startup with 30K LOCs in Clojurescript
  • Author of Klipse - a simple client-side code evaluator pluggable on any web page
KLIPSE
  • A Web consultant: Full-Stack, clojure{,script}, ruby{, on rails}, javascript, react
me

A brief history of Functional Programming

1930: λ-calculus

  • Alonzo Church discovers the λ-calculus
  • Everything is a (anonymous) function with one argument
  • No names in the language - only function argument
  • Even numbers are expressed as functions
  • 0 := λfx.x
  • 1 := λfx.f x
  • 2 := λfx.f (f x)

1958: LISP

  • John McCarthy invents LISP
  • It is the 1st FP language
  • Everything is a S-Expression: (+ 1 2 3) instead of 1 + 2 + 3 or +(1,2,3)
  • Only 7 terms: CAR, CDR, ATOM, LAMBDA, LABEL, COND, QUOTE

1995: Javascript the language of the browser

  • Brendan Eich is recruited by Netscape to do "scheme in the browser"
  • Eventually, he invents Javascript
  • Functions are 1st class citizens

2004: Scala - FP on the JVM

  • 2004 - Martin Odersky invents Scala
  • A JVM statically typed language with functional programming support
  • It is very complicated!!!

A brief history of Functional Programming (cont.)

  • 2007 - Rich Hickey invents Clojure - A practical dialect of LISP on top of JVM
  • 2011 - ClojureScript - Clojure rocks, Javascript Reaches!
  • 2013 - Facebook creates react.js - A functional javascript frontend framework
  • 2015 - Dan Abramov invents redux - A javascript library that imposes FP constraints on a frontend app

Functional Programming in practice - React.js

Insights

  • The UI is a (pure) function of the state (virtual DOM).
  • Functions compose very well.

Paradigms

  • Write functions that create UI components and compose the functions.
  • The state is a plain Javascript Object.
  • Do not mutate the state, create a new version of it (immutability).
  • Write functions that manipulate the state instead of the DOM (reduce the presence of the dirty stuff).
  • The framework will update the DOM efficiently.
  • Separate UI components from Logic components.
  • Create a new markup language - JSX - that is transpiled into javascript.

Pure UI components

We should try to maximize the usage of pure components e.g. components written as functions with no state that depends only on their props.


ReactDOM.render(React.createElement(Square, {value: 42,
                                             onClick: () => alert("clicked")}), klipse_container)


<Square
value={26}
  onClick={() => alert("clicked")}
/>


You can do almost everything with JSX, but there are some pitfalls.
Be sure to check this interactive JSX guide

Exercise: display the value when the square is clicked

Controlled components

The react state is the single source of truth.
The state of the html element is updated by a react handler that listens to onChange type of events.


<TextInput/>

Exercises:
1. Convert the input to upper case
2. Prepend input: to the input

DOM interaction

Sometimes (not too often!), we need to interact directly with the DOM e.g. for manipulating a canvas element.
React allows us to get access to the DOM elements that are rendered.


<MyCanvas bgColor="blue"/>

Exercises:
1. Add a button that cleans the canvas
2. Add more params to props: fill color, point thickness…​
3. Add an element that displays the number of points in the canvas

Logic components

class SquareLogic extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      val: 10
    }
  }
  increment() {
    let state = R.assoc('val', this.state.val + 1, this.state)
    this.setState(state)
  }
  render() {
    return (
      <Square value={this.state.val}
      onClick= {() => this.increment()}/>
      )
  }
}
window.SquareLogic = SquareLogic
<SquareLogic/>

Exercises:
1. Draw 4 squares instead of 1
2. On odd squares, increment - on even squares, decrement
3. Display the number of clicks
4. Add a reset button
5. Add an undo button

Redux - React influenced by ClojureScript

Three principles (constraints):

  • Single source of truth
  • State is read-only
  • Changes are made with pure functions

Many Positive consequences:

  • Easy to test
  • Easy to track actions
  • Easy to visualize state of the app
  • Time travel (undo)
  • Send state over the wire
  • Store/Retrieve state from localStorage

Redux in action

Component

const mapDispatchToProps = (dispatch) => ({
  onClick() {
    dispatch(incrementSquareValue())
  }
})
const mapStateToProps = (state) => ({
  value: state.square.value
})
window.SquareRedux = ReactRedux.connect(mapStateToProps, mapDispatchToProps)(Square)

Actions

incrementSquareValue = () => ({
  type: 'INCREMENT_SQUARE_VALUE'
})

Reducers

square = (state={value: 0}, action) => {
  switch(action.type) {
    case 'INCREMENT_SQUARE_VALUE':
      return R.assoc('value', state.value + 1, state)
    default:
      return state
                    }
}
app = Redux.combineReducers({square: square})

The store

store = Redux.createStore(app)

The App

<ReactRedux.Provider store={store}>
  <SquareRedux/>
</ReactRedux.Provider>


Playground

// store.dispatch(incrementSquareValue())
// store.getState()

Discussion and Questions

questions

What else?

  • unit tests
  • redux dev tools
  • redux middlewares
  • redux thunks
  • watch react videos to see what crazy things people can do
  • ES6 tricks
  • props validation

Small project

Write a react redux application with:
1. A Game page: Tic Tac Toe
2. A Params page: Display groups of parameters as specified by a dynamic JSON. The parameters should be grouped according to the first part of their name. The required controls are: text input, number input, checkbox and dropdown.
3. A header that display the name of the current page and allow to switch pages

Remarks:
1. BootStrap your react project with Create React App
2. You must write unit tests for your reducers and your components with jest and enzyme
3. Use yarn
4. Use ramda for data manipulation

Here is an example of a JSON that defines the params

const params = [
  {
    "Name":"Basics.Title",
    "Type":"TextInput",
    "Value":"Hello World",
    "Description":"Title of the book"
  },
  {
    "Name":"Advanced.Color_Cover",
    "Type":"Checkbox",
    "Value":["Red", "Black"],
    "Description":"Colors of the cover",
    "ListValues":["Red","Green","Blue","Black"],
  },
  {
    "Name":"Basics.Color",
    "VariableType":"Dropdown",
    "Value":"Red",
    "Description":"Color of the font",
    "ListValues":["Red","Green","Blue","Black"],
  },
  {
    "Name":"Basics.budget",
    "Type":"Number",
    "Value":95.2,
    "Description":"Budget",
    "Min":1.0,
    "Max":100.0,
    "Step":0.5,
  },
]

powered by Klipse /