Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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.

Matteo Ronchi

April 30, 2016
Tweet

More Decks by Matteo Ronchi

Other Decks in Programming

Transcript

  1. IN REACT
    HIGHER ORDER COMPONENTS

    View full-size slide

  2. ✓ @CEF62 • GITHUB/CEF62
    ✓ SENIOR ENGINEER @
    ✓ ITALIAN REACT & ANGULAR COMMUNITIES

    View full-size slide

  3. FROM DOCUMENTS
    TO COMPONENTS

    View full-size slide

  4. HYPERTEXT MARKUP LANGUAGE

    Title Text
    Some text about something

    View full-size slide

  5. AJAX & DOM MANIPULATION




    <br/>$(document).ready(() => {<br/>$.ajax(‘my-url.php’)<br/>.done((data) => {<br/>$(‘#my-title’).text(data.title)<br/>$(‘#my-contents’).text(data.contents)<br/>})<br/>})<br/>

    View full-size slide

  6. ANGULARJS



    <br/>angular.module(‘app’, [])<br/>.directive(‘myPage’, function($http) {<br/>return {<br/>scope: { myUrl: ‘@’}<br/>template:<br/>`<div><br/><h1>{{myTitle}}</h1><br/><p>{{myContents}}</p><br/></div>`<br/>link: function(scope) {<br/>$http.get(scope.myUrl).success((data) => {<br/>scope.myTitle = data.title<br/>scope.myContents = data.contents<br/>})<br/>}<br/>}<br/>})<br/>

    View full-size slide

  7. REACT

    <br/>class App extends React.Component {<br/>componentWillMount() {<br/>axios.get(this.props.myUrl)<br/>.then(({ title, contents }) => {<br/>this.setState({ title, contents })<br/>})<br/>}<br/>render() {<br/>return (<br/><div><br/><h1>{this.state.title}</h1><br/><p>{this.state.contents}</p><br/></div><br/>)<br/>}<br/>}<br/>ReactDOM.render(<br/><App myUrl=“my-url.php” />,<br/>document.getElementById(‘root’)<br/>)<br/>

    View full-size slide

  8. ALL MODERN
    FRAMEWORKS
    ARE
    COMPONENT
    ORIENTED
    •REACT
    •ANGULAR 2
    •POLYMER

    View full-size slide

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

    View full-size slide

  10. COMPONENTS ARE
    • Composable
    • Encapsulated
    • Reusable
    • Easy to design

    View full-size slide

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

    View full-size slide

  12. STATELESS FUNCTIONAL COMPONENTS
    const Label = (props) => {props.children}
    const Icon = (props) => {
    return (

    {props.label}

    )
    }
    const App = () =>
    Some label


    View full-size slide

  13. COMPONENT
    LIFECYCLE

    View full-size slide

  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) {}
    }

    View full-size slide

  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() {}
    }

    View full-size slide

  16. CONTEXT-
    AWARE,
    STATEFUL,
    DYNAMIC,
    POWERFUL
    CONTAINER
    COMPONENTS

    View full-size slide

  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 (

    {this.props.label}

    )
    }
    }

    View full-size slide

  18. REDUCE CODE
    BOILERPLATE

    View full-size slide

  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 {this.state.info.text}
    }
    }
    class User extends React.Component {
    constructor(props) { this.state = { user: {} } }
    componentWillMount() {
    axios.get(this.props.url).then(
    ({ data }) => this.setState({ user: data })
    )
    }
    render() {
    return {this.state.user.name}
    }
    }

    View full-size slide

  20. REACT MIXINS

    View full-size slide

  21. MIXINS
    const LoadDataMixin = {
    loadData(url, targetField) {
    axios.get(url).then(
    ({ data }) => this.setState({ [targetField]: data })
    )
    }
    }

    View full-size slide

  22. MIXINS
    const BoxInfo = React.createClass({
    mixins: [LoadDataMixin],
    getInitialState() { return { info: {} } },
    componentWillMount() {
    this.loadData(this.props.url, 'info')
    },
    render() { return {this.state.info.text} }
    })
    const UserPanel = React.createClass({
    mixins: [LoadDataMixin],
    getInitialState() { return { user: {} } },
    componentWillMount() {
    this.loadData(this.props.url, 'user')
    },
    render() { return {this.state.user.name} }
    })

    View full-size slide

  23. HIGHER ORDER FUNCTIONS

    View full-size slide

  24. — Marijn Haverbeke (eloquent javascript)
    HIGHER-ORDER FUNCTIONS
    ALLOW US TO ABSTRACT
    OVER ACTIONS, NOT JUST
    VALUES.


    View full-size slide

  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!

    View full-size slide

  26. (TO)HIGHER
    ORDER
    COMPONE
    NTS
    FROM HIGHER
    ORDER FUNCTIONS

    View full-size slide

  27. const Wrapped = () => Wrapped Comp
    const wrapper = (Comp) => () => {
    return
    }
    const FinalComponent = wrapper(Wrapped)
    const App = () => {
    return (



    )
    }

    View full-size slide

  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) => {props.data.text})
    const User = loadData((props) => {props.data.name})

    View full-size slide

  29. DECORATOR PROPOSAL
    @loadData
    class Box extends React.Component {
    render() {
    return {this.props.data.text}
    }
    }
    @loadData
    class User extends React.Component {
    render() {
    return {this.props.data.name}
    }
    }

    View full-size slide

  30. - Declarative
    - Customizable
    - Easy to read
    - Enforce composition
    HOC VS MIXINS
    Imperative -
    Favors inheritance -
    Hard to read -
    Method names collision -
    Access component state -

    View full-size slide

  31. BEST PRACTICES
    HIGHER ORDER COMPONENTS
    • Expose wrapped component
    • Pass props to wrapped component
    • Expose statics methods and props from wrapped component

    View full-size slide

  32. CODE
    SEE ONLINE

    View full-size slide

  33. THANKS!
    @CEF62

    View full-size slide