Higher Order Components in React at italian jsDay 2016

Higher Order Components in React at italian jsDay 2016

React is “a Javascript library for building user interfaces”. The core of React follows many concepts of Functional Programming, code composition is one of its main features. In React there are 2 main types of building blocks: 'stateful' components and 'stateless' components. The former type is defined by elements owning the application logic; this kind of components often is bound to external elements and owns a state. The latter type is composed of 'pure' components where all dynamic data is received from their props and no internal state is defined. This approach often produces replication of functionalities in several components; 'Higher Order Components' (HoC) is the natural solution for this scenario and is a more functional alternative to traditional React 'mixins'. An HoC abstracts component functionalities and offers an easy way to compose them when required making the code more maintainable and avoiding duplicates. During the session we will see how to implements this pattern taking attention on its pros and cons.

5171121655bc1a7cc89d16a7a3ce8885?s=128

Matteo Ronchi

May 12, 2016
Tweet

Transcript

  1. higher order components In react 2016

  2. Senior engineer @ . Italian react & angular communities Matteo

    Ronchi @cef62 github/cef62
  3. From Documents to components

  4. <div> <h1>Title Text</h1> <p>Some text about something</p> </div> HyperText Markup

    Language
  5. <div> <h1 id=“my-title”></h1> <p id=“my-contents”></p> </div> <script type=“text/javascript”> $(document).ready(() =>

    { $.ajax(‘my-url.php’) .done((data) => { $(‘#my-title’).text(data.title) $(‘#my-contents’).text(data.contents) }) }) </script> jQuery
  6. <div ng-app=“app”> <my-page my-url=“my-url.php”></my-page> </div> <script type=“text/javascript”> angular.module(‘app’, []).directive(‘myPage’, function($http)

    { return { scope: { myUrl: ‘@’} template: `<div> <h1>{{myTitle}}</h1> <p>{{myContents}}</p> </div>` link: function(scope) { $http.get(scope.myUrl).success((data) => { scope.myTitle = data.title scope.myContents = data.contents }) } } }) </script> AngularJS
  7. <div id=“root” /> <script type=“text/javascript”> class App extends React.Component {

    componentWillMount() { axios.get(this.props.myUrl).then(({ title, contents }) => { this.setState({ title, contents }) }) } render() { return ( <div> <h1>{this.state.title}</h1> <p>{this.state.contents}</p> </div> ) } } ReactDOM.render(<App myUrl=“my-url.php” />, document.getElementById(‘root’)) </script> React
  8. react angular 2 polymer all modern frameworks are component oriented

  9. Everything is a Component an application is a tree of

    components
  10. Components are • Composable • Encapsulated • Reusable • Easy

    to design
  11. presentational components small, reusable, pure functions, easy to test

  12. const Label = (props) => <h1>{props.children}</h1> const Icon = (props)

    => { return ( <i className="fa fa-anchor"> {props.label} </i> ) } const App = () => <div> <Label>Some label</Label> <Icon label="ready to sail" /> </div> Stateless Functional Components
  13. Component lifecycle

  14. class MyComponent extends React.Component { // Component Initialization constructor(props) {}

    // component ready to be mounted componentWillMount() {} // Props have changed componentWillReceiveProps(nextProps) {} // prevent rendering if not required shouldComponentUpdate(nextProps, nextState) {} // Prepare before rendering componentWillUpdate(nextProps, nextState) {} } Component Lifecycle
  15. class MyComponent extends React.Component { // create/update the component render()

    {} // Component DOM it’s been created componentDidMount() {} // Component DOM it’s been updated componentDidUpdate(prevProps, prevState) {} // cleanup before component destruction componentWillUnmount() {} } Component Lifecycle
  16. Container Components Context-aware, stateful, dynamic, powerful

  17. class Toggle extends React.Component { constructor(props) { super(props) this.state =

    { enabled: false } this.toggle = this.toggle.bind(this) } toggle() { this.setState({ enabled: !this.state.enabled }) } render() { const cls = this.state.enabled ?'btn-success':'btn-danger' return ( <button className={‘btn ‘ + cls} onClick={this.toggle}> {this.props.label} </button> ) } } Stateful Components
  18. REDUCE code boilerplAte

  19. class Box extends React.Component { constructor(props) { this.state = {

    info: {} } } componentWillMount() { axios.get(this.props.url).then( ({ data }) => this.setState({ info: data }) ) } render() { return <div>{this.state.info.text}</div> } } class User extends React.Component { constructor(props) { this.state = { user: {} } } componentWillMount() { axios.get(this.props.url).then( ({ data }) => this.setState({ user: data }) ) } render() { return <div>{this.state.user.name}</div> } } Components Share Functionalities
  20. REACT mixins

  21. const LoadDataMixin = { loadData(url, targetField) { axios.get(url).then( ({ data

    }) => this.setState({ [targetField]: data }) ) } } React Mixins
  22. const BoxInfo = React.createClass({ mixins: [LoadDataMixin], getInitialState() { return {

    info: {} } }, componentWillMount() { this.loadData(this.props.url, 'info') }, render() { return <div>{this.state.info.text}</div> } }) const UserPanel = React.createClass({ mixins: [LoadDataMixin], getInitialState() { return { user: {} } }, componentWillMount() { this.loadData(this.props.url, 'user') }, render() { return <div>{this.state.user.name}</div> } }) React Mixins
  23. higher order functions

  24. — Marijn Haverbeke ( eloquent javascript ) Higher-order functions allow

    us to abstract over actions, not just values.
  25. function applyVat(vat) { return (value) => ((vat + 100) /

    100) * value } const applyVat22 = applyVat(22) console.log(applyVat22(100)) // print -> 122 function maybe(condition, action) { if (condition) { action() } } const action = (msg) => () => console.log(msg) maybe(true, action(`It works!`)) maybe(false, action(`Doesn't work!`)) // print -> It works! HoF
  26. From Higher order functions ( TO ) Higher order components

  27. const Wrapped = () => <h1>Wrapped Comp</h1> const wrapper =

    (Comp) => () => { return <div><Comp /></div> } const FinalComponent = wrapper(Wrapped) const App = () => { return ( <div> <FinalComponent /> </div> ) } Simple HoC
  28. const loadData = (Component) => { return class LoadDataWrapper extends

    React.Component { constructor(props) { this.state = { data: {} } } componentWillMount() { axios.get(this.props.url).then( ({ data }) => this.setState({ data }) ) } render() { const props = Object.assign({}, this.props, this.state) return React.createElement(Component, props) } } } const Box = loadData((props) => <div>{props.data.text}</div>) const User = loadData((props) => <div>{props.data.name}</div>) Reduce Duplication of Code
  29. @loadData class Box extends React.Component { render() { return <div>{this.props.data.text}</div>

    } } @loadData class User extends React.Component { render() { return <div>{this.props.data.name}</div> } } // See https://github.com/wycats/javascript-decorators Decorator Proposal
  30. HoC vs Mixins - Declarative - Customizable - Easy to

    read - Enforce composition Imperative - Favors inheritance - Hard to read - Method names collision - Access component state -
  31. HoC - Best Practices • Expose wrapped component • Pass

    props to wrapped component • Expose statics methods and props from wrapped component
  32. code See online

  33. thanks ! @CEF62