Higher Order Components in React at Voxxed Days Ticino 2016

Higher Order Components in React at Voxxed Days Ticino 2016

see code at https://gist.github.com/cef62/23b37d0fb8b47c0ed9c5a40a0ae15414

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

April 30, 2016
Tweet

Transcript

  1. IN REACT HIGHER ORDER COMPONENTS

  2. ✓ @CEF62 • GITHUB/CEF62 ✓ SENIOR ENGINEER @ ✓ ITALIAN

    REACT & ANGULAR COMMUNITIES
  3. FROM DOCUMENTS TO COMPONENTS

  4. HYPERTEXT MARKUP LANGUAGE <div> <h1>Title Text</h1> <p>Some text about something</p>

    </div>
  5. AJAX & DOM MANIPULATION <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>
  6. ANGULARJS <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>
  7. REACT <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>
  8. ALL MODERN FRAMEWORKS ARE COMPONENT ORIENTED •REACT •ANGULAR 2 •POLYMER

  9. AN APPLICATION IS A TREE OF COMPONENTS EVERYTHING IS A

    COMPONENT
  10. COMPONENTS ARE • Composable • Encapsulated • Reusable • Easy

    to design
  11. SMALL, REUSABLE, PURE FUNCTIONS, EASY TO TEST PRESENTATIONAL COMPONENTS

  12. STATELESS FUNCTIONAL COMPONENTS 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>
  13. COMPONENT LIFECYCLE

  14. COMPONENT LIFECYCLE 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) {} }
  15. COMPONENT LIFECYCLE 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() {} }
  16. CONTEXT- AWARE, STATEFUL, DYNAMIC, POWERFUL CONTAINER COMPONENTS

  17. STATEFUL COMPONENTS 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> ) } }
  18. REDUCE CODE BOILERPLATE

  19. COMPONENTS SHARE FUNCTIONALITIES 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> } }
  20. REACT MIXINS

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

    data }) => this.setState({ [targetField]: data }) ) } }
  22. MIXINS 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> } })
  23. HIGHER ORDER FUNCTIONS

  24. — Marijn Haverbeke (eloquent javascript) HIGHER-ORDER FUNCTIONS ALLOW US TO

    ABSTRACT OVER ACTIONS, NOT JUST VALUES. ” “
  25. HOF 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 works!`)) // print -> It works!
  26. (TO)HIGHER ORDER COMPONE NTS FROM HIGHER ORDER FUNCTIONS

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

    (Comp) => () => { return <div><Comp /></div> } const FinalComponent = wrapper(Wrapped) const App = () => { return ( <div> <FinalComponent /> </div> ) }
  28. REDUCE DUPLICATION OF CODE 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>)
  29. DECORATOR PROPOSAL @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> } }
  30. - Declarative - Customizable - Easy to read - Enforce

    composition HOC VS MIXINS Imperative - Favors inheritance - Hard to read - Method names collision - Access component state -
  31. BEST PRACTICES HIGHER ORDER COMPONENTS • Expose wrapped component •

    Pass props to wrapped component • Expose statics methods and props from wrapped component
  32. CODE SEE ONLINE

  33. THANKS! @CEF62