React.js for its Enthusiasts

React.js for Ruby Gods

What to Talk About ?

State lifecycle becomes untrackable

Confusing client-side operations

Too much effort for creating HTML trees

Emergency Call for :

States and Props are brothers

Everything is a component

Virtual-DOM becomes the hero

The solution comes as

Controllable data lifecycle 

Seperation of Concerns

Performance

Our first component

Controllable data lifecycle 

Seperation of Concerns

Performance

var OurFirstComponent = React.createClass({
   render : function () {
      return <p>Our first component</p>
   }
});

Our first component

React.createClass : Generate a DOM element

render : Glue for DOM elements

Return a HTML element in JS

var OurFirstComponent = React.createClass({
   render : function () {
      return <p>Our first component</p>
   }
});

Our first component

Attached component into a DOM element wrapper

var OurFirstComponent = React.createClass({
   render : function () {
      return <p>Our first component</p>
   }
});
ReactDOM.render(<OurFirstComponent/>, mountNode);
var mountNode = document.getElementById('ourFirstComp');

or

ReactDOM.render(<OurFirstComponent/>, document.getElementById('ourFirstComp'));

The working example of our component

What about more components ?

Composable components made easy!

var OurFirstComponent = React.createClass({
   render : function () {
      return <p>Our first component</p>
   }
});

var OurSecondComponent = React.createClass({
   render : function () {
      return <p>Our second component</p>
   }
});

var OurSetOfComponents = React.createClass({
   render : function () {
      return (
         <OurFirstComponent/>
         <OurSecondComponent/>
      )
   }
});

How to pass data through components

React.createClass : Generate a DOM element

Props from parent to children

var OurFirstComponent = React.createClass({
   render : function () {
      return <p>Our {this.props.order} component</p>
   }
});

var OurSecondComponent = React.createClass({
   render : function () {
      return <p>Our {this.props.order} component</p>
   }
});

var OurSetOfComponents = React.createClass({
   render : function () {
      return (
         <div>
            <OurFirstComponent order="first"/>
            <OurSecondComponent order="second"/>
         </div>
      )
   }
});

Managing Events like Prop Transition

Context never overflows

var CounterButton = React.createClass({
   getInitialState : function () {
      return {
         counter : 0
      }
   },
   increment : function () {
      var currentCounter = this.state.counter;
      this.setState({counter : currentCounter + 1});
   },
   render : function () {
      return <button onClick={this.increment}>You click for {this.state.counter} time!</button>
   }
});

If it becomes two ?

var FirstCounterButton = React.createClass({
   getInitialState : function () {
      return {
         counter : 0
      }
   },
   increment : function () {
      var currentCounter = this.state.counter;
      this.setState({counter : currentCounter + 1});
   },
   render : function () {
      return <button onClick={this.increment}>You click for {this.state.counter} time!</button>
   }
});
var SecondCounterButton = React.createClass({
   getInitialState : function () {
      return {
         counter : 0
      }
   },
   increment : function () {
      var currentCounter = this.state.counter;
      this.setState({counter : currentCounter + 1});
   },
   render : function () {
      return <button onClick={this.increment}>You click for {this.state.counter} time!</button>
   }
});

A component's specs

A component's specs

render

Type: Required

Specification: Needs to return a single child element

Restrictions : No use of null or false returnings

render : function () {
   return (
      <article>
          <p>
             <ArticleItem/>
          </p>
      </article>
   )
}

A component's specs

getInitialState

Type: Optional

Specification: Called before component is mounted

Return value is used for the initial state value

getInitialState : function  () {
   return {
      counter : 0
   }
}

A component's specs

getDefaultProps

Type: Optional

Specification: Invoked when the class/component is created

Cannot rely on this.props

getDefaultProps: function() {
    return {
      value: 'default value'
    }
}

A component's lifecycle

propTypes

Type: Optional

Specification: Allows developer to define the prop types before they are sent

Using this is a good best practice

var SomeComponent = React.createClass({
  propTypes: {
    children: React.PropTypes.element.isRequired
  },
  render: function() {
    return (
      <div>
        {this.props.children} // This must be exactly one element or it will warn.
      </div>
    );
  }

});

A component's lifecycle

statics

Type: Optional

Specification: Allows developer to define some static methods to call by the component

A pragmatic way

var SomeComponent = React.createClass({
  statics: {
    someMethod: function() {
      return 1 === 1;
    }
  },
  render: function() {}
});

MyComponent.someMethod();  // true

A component's lifecycle

A component's lifecycle

componentWillMount

Type: Optional

Specification: Occurs just before the component is rendered

Used for interactions for the state changes (exm. setState)

componentWillMount : function () {
   var data = null; 
   $.ajax('/someUrl', function (result) {
      data = result;
   });
}

A component's lifecycle

componentDidMount

Type: Optional

Specification: Occurs just after the component was rendered

The child components' methods are invoked before the parents' methods

componentDidMount : function () {
   var data = null; 
   $.ajax('/someUrl', function (result) {
      data = result;
   });
}

A component's lifecycle

componentWillReceiveProps

Type: Optional

Specification: Invoked when the component receive new props

It can be used just before rendering the component with the next props

componentWillReceiveProps: function(nextProps) {
  this.setState({
    likesIncreasing: nextProps.likeCount > this.props.likeCount
  });
}

A component's lifecycle

shouldComponentUpdate

Type: Optional

Specification: Invoked when the component receive new props and state

It can be used to return false if the components is needed to be updated

shouldComponentUpdate: function(nextProps, nextState) {
  return nextProps.id !== this.props.id;
}

A component's lifecycle

componentWillUpdate

Type: Optional

Specification: Invoked when the component receive new props and state

It is not an initial render method

componentWillUpdate: function(nextProps, nextState) {
  return nextProps.id !== this.props.id;
}

A component's lifecycle

componentDidUpdate

Type: Optional

Specification: Invoked just after the component rendered and put into DOM

Make DOM operations with this 

componentDidUpdate: function(prevProps, prevState) {
  return prevProps.key === prevState[0].key;
}

A component's lifecycle

componentWillUnmount

Type: Optional

Specification: Invoked just before the component unmounted

A cleaning method

componentWillUnmount: function() {
    clearInterval(this.timer);
}
MyReactComponent = React.createClass({
    getInitialState: function(){
        return {};
    },    
    getDefaultProps: function(){
        return {};
    },
    render: function(){
        return (<div></div>);
    },
    mixins: [],
    statics: {
        aStaticFunction: function(){}
    },
    componentWillMount: function(){
        // Calling setState here does not cause a re-render
    },
    componentDidMount: function(){
        // You now have access to this.getDOMNode()
    },
    componentWillReceiveProps: function(nextProps){},
    shouldComponentUpdate: function(nextProps, nextState){
        return true;
    },
    componentWillUpdate: function(nextProps, nextState){
        // You cannot use this.setState() in this method
    },
    componentDidUpdate: function(prevProps, prevState){
    },
    componentWillUnmount: function(){
    }
});

Step by Step

  • Render "Hello World"
  • Render a few nested plain HTML elements
  • Refactor hello world into two separate components: Hello and World
  • Make World accept an optional prop called "name"
  • Create a static array and pass it as a prop to the World component and render them like Hello <name>
  • Make a counter component separately.
  • Separate three components as IncrementButton, DecrementButton and CounterLabel
  • Keep state within a wrapper component called Counter and pass down the state into nested components
  • Include Counter into your App component

Sources

  • https://reactjs.org/
  • https://facebook.github.io/react/docs/getting-started.html
  • http://ricostacruz.com/cheatsheets/react.html

Thank you

github.com/hwclass

twitter.com/hwclass

Questions?

React for Ruby Gods

By Barış Güler

React for Ruby Gods

  • 440
Loading comments...

More from Barış Güler