React notes

Learn once, write anywhere.

Facebook Engineering blog

Create a project

Use create-react-app.

npm install -g create-react-app
create-react-app <app name>

Basics

Props vs state

props stores read-only data is passed from the parent.
It belongs to the parent and cannot be changed by its children.
This data should be considered immutable.

state stores data that is private to the component.
It can be changed by the component.
The component will rerender itself when the state is updated.

import React from 'react'


export class MyComponent extends React.Component {

  constructor(props) {
    super(props)

    this.state = {
      somekey: 'somevalue'
    }

    this.onSomething.bind(this)
  }

  onSomething() {
    // update state, it would cause rerender
    this.setState({somekey: 'anothervalue'})
  }

  render() {
    return <div
      something={this.state.something}
      onClick={this.onSomething}
    >{this.props.text}</div>
  }
}

Setting the state:

this.setState({ foo: bar });

this.setState((prevState, props) => { ... })
onChange(e) {
  e.preventDefault();
  this.setState({[e.target.name]: e.target.value});
}

Bindings

The best place for methods bindings is class constructor:

class User {
  constructor(fname, lname) {
    this.fname = fname;
    this.lname = lname;
    this.getName.bind(this);
  }
  getName() {
    return this.fname + ' ' + this.lname;
  }
}

Or use arrow function:

class User {
  constructor(fname, lname) {
    this.fname = fname;
    this.lname = lname;
    this.getName.bind(this);
  }
  getName = () => {
    return this.fname + ' ' + this.lname;
  }
}

JSX

<div className="App">
  {this.state.list.map(
    item =>
    <p>
      {item.title}
    </p>
  )}
</div>

Lifecycle methods

Mountilg:

constructor - is called when an instance of the component is created and inserted in the DOM (component mounting).

render - is called during the mount process and when the component updates (when state or props changes).

componentWillMount - is called before the render method.

componentDidMount - is called after the render method, perfect for asynchronous requests.

Update (when the state changes):

Unmount:

Communication with a server

Use fetch:

fetch("http://example.com").then(
  response => response.json()
).then(
  result => this.parse(result)
).atch(
  error => error
)

Or axious.

ENV variables

Add variables to .env:

REACT_APP_SOKE_KEY=somevalue

Access in js with ${process.env.REACT_APP_SOME_KEY}.

Project structure

src/
  index.js
  index.css
  components/
    App/
      index.js
      test.js
      index.css
    Button/
      index.js
      test.js
      index.css

Testing

For unittests use Enzyme.

Redux

Redux is a predictable state container for JavaScript apps.

Store

Actions

Async actions. FB login example.

Reducer

Composition.

react-redux

React native

Libraries

material-ui

co

The ultimate generator based flow-control goodness.

See https://github.com/tj/co.

co(function* () {

  let result = yield someFunc()

  return result

}).then(function (value) {
  console.log(value)
}, function (err) {
  console.error(err)
})

Where someFunc returns a promise.

Code snippets

FB login

A fb login redux action:

function fbLoginAction() {

  const fbElementID = 'fb-root'
  const scope = 'public_profile, email'

  const _login = (dispatch) => {
    FB.login(({authResponse, status}) => {
      if (status == 'connected') {
        let {accessToken, userID} = authResponse
        return axios(
          {
            url: `${SERVER_URL}/fb`,
            method: 'POST',
            headers: {
              'Accept': 'application/json',
              'Content-Type': 'application/json; charset=utf-8'
            },
            data: {
              accessToken,
              userID
            }
          }
        ).then(response => dispatch(initializeUserAction(response.data)))
      }
    }, { scope })
  }

  return dispatch => {
    /* load fb SDK */

    let fbRoot = document.getElementById(fbElementID)
    if (!fbRoot) {
      fbRoot = document.createElement('div')
      fbRoot.id = 'fb-root'
      document.body.appendChild(fbRoot)

      window.fbAsyncInit = () => {
        FB.init({
          appId: FB_APP_ID,
          xfbml: false,
          cookie: false,
          version: 'v2.3',
        })
        _login(dispatch)
      }

      ((d, s, id) => {
        const element = d.getElementsByTagName(s)[0];
        const fjs = element;
        let js = element;
        if (d.getElementById(id)) {return;}
        js = d.createElement(s); js.id = id;
        js.src = '//connect.facebook.net/en_US/sdk.js';
        fjs.parentNode.insertBefore(js, fjs);
      })(document, 'script', 'facebook-jssdk');
    } else {
      _login(dispatch)
    }
  }
}

Instruments

babel, webpack

See ES6 notes / ES6(ES7) -> ES5.

Development server using node/express

npm install --save-dev express

server.js:

const express = require('express')
const path = require('path')


const staticFolder = path.join(__dirname, 'build')


const app = express()


app.use(express.static(staticFolder, {index: 'index.html'}))


app.listen(8000, function () {
  console.log('Listening on port 8000!')
})

Vocabulary

Isomorphic

React native

React.js Essentials by Artemij Fedosejev
The Road to learn React by Robin Wieruch
http://redux.js.org/

Licensed under CC BY-SA 3.0