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

Add Superpowers to your React components using ES7 decorators

Add Superpowers to your React components using ES7 decorators

Siddharth Kshetrapal

January 14, 2017
Tweet

More Decks by Siddharth Kshetrapal

Other Decks in Technology

Transcript

  1. const firstName = 'siddharth' const lastName = 'kshetrapal' const fullName

    = firstName + ' ' + lastName const fullName = `${firstName} ${lastName}` Template literals
  2. class Human { constructor(name) { this.name = name } speak()

    { console.log(`Hi! My name is ${this.name}`) } } ES 6 classes
  3. class Human { constructor(name) { this.name = name } speak()

    { console.log(`Hi! My name is ${this.name}`) } } const siddharth = new Human('siddharth') siddharth.speak() // Hi! My name is siddharth ES 6 classes
  4. function log(message) { return console.log(message) } const log = (message)

    => { return console.log(message) } arrow functions
  5. function log(message) { return console.log(message) } const log = message

    => { return console.log(message) } arrow functions
  6. arrow functions function log(message) { return function () { return

    console.log(message) } } const log = message => { return () => { return console.log(message) } }
  7. arrow functions function log(message) { return function () { return

    console.log(message) } } const log = message => { return () => console.log(message) }
  8. arrow functions function log(message) { return function () { return

    console.log(message) } } const log = message => () => console.log(message)
  9. class Human { constructor(name) { this.name = name } speak()

    { console.log(`Hi! My name is ${this.name}`) } }
  10. class Human { constructor(name) { this.name = name } speak()

    { console.log(`Hi! My name is ${this.name}`) } } const siddharth = new Human('siddharth') siddharth.speak() // Hi! My name is siddharth
  11. ... speak() { console.log(`Hi! My name is ${this.name}`) } }

    const siddharth = new Human('siddharth') siddharth.speak = () => {console.log('Hi! My name is dum dum')
  12. ... speak() { console.log(`Hi! My name is ${this.name}`) } }

    const siddharth = new Human('siddharth') siddharth.speak = () => {console.log('Hi! My name is dum dum') siddharth.speak() // Hi! My name is dum dum
  13. class Human { constructor(name) { this.name = name } @readonly

    speak() { console.log(`Hi! My name is ${this.name}`) } }
  14. const readonly = (target, key, descriptor) => { console.log(target, key,

    descriptor) } /* Human {}, 'speak', { value: [Function: speak], writable: true, enumerable: false, configurable: true } */
  15. @readonly speak() { console.log(`Hi! My name is ${this.name}`) } }

    const siddharth = new Human('siddharth') siddharth.speak = () => {console.log('Hi! My name is dum dum'} siddharth.speak() // Hi! My name is siddharth
  16. class Human { constructor(name) {this.name = name} useAngular() { console.log('writing

    angular code') } } siddharth.writeAngular() // writing angular code
  17. class Human { constructor(name) {this.name = name} @deprecate useAngular() {

    console.log('writing angular code') } } siddharth.writeAngular() // speak@Human: this feature will be deprecated soon! // writing angular code
  18. const deprecate = (target, key, descriptor) => { const original

    = descriptor.value const name = `${target.constructor.name}.${key}` }
  19. const deprecate = (target, key, descriptor) => { const original

    = descriptor.value const name = `${target.constructor.name}.${key}` const message = 'this feature will be deprecated soon!' descriptor.value = () => { console.log(`${name} : ${message}`) original.apply(this, arguments) } }
  20. const deprecate = (target, key, descriptor) => { const original

    = descriptor.value const name = `${target.constructor.name}.${key}` const message = 'this feature will be deprecated soon!' descriptor.value = () => { console.log(`${name} : ${message}`) original.apply(this, arguments) } return descriptor }
  21. class Human { constructor(name) {this.name = name} @deprecate useAngular() {

    console.log('writing angular code') } } siddharth.writeAngular() // speak@Human: this feature will be deprecated soon! // writing angular code
  22. class Human { constructor(name) {this.name = name} @deprecate('will be deprecated

    in v2.0.0') useAngular() { console.log('writing angular code') } } siddharth.writeAngular() // speak@Human: will be deprecated in v2.0.0 // writing angular code
  23. syntax @decorator = function const decorator = (target, key, descriptor)

    => { } @decorator(argument) = higher order function const decorator = (argument) => { return (target, key, descriptor) => { } }
  24. syntax @decorator = function const decorator = (target, key, descriptor)

    => { } @decorator(argument) = higher order function const decorator = argument => (target, key, descriptor) => { }
  25. @deprecate = function const deprecate = (target, key, descriptor) =>

    { const original = descriptor.value const name = `${target.constructor.name}.${key}` const message = 'this feature will be deprecated soon!' descriptor.value = () => { console.log(`${name} : ${message}`) original.apply(this, arguments) } return descriptor }
  26. @deprecate(message) = higher order function const deprecate = message =>

    (target, key, descriptor) => { const original = descriptor.value const name = `${target.constructor.name}.${key}` const message = 'this feature will be deprecated soon!' descriptor.value = () => { console.log(`${name} : ${message}`) original.apply(this, arguments) } return descriptor }
  27. @deprecate(message) = higher order function const deprecate = message =>

    (target, key, descriptor) => { const original = descriptor.value const name = `${target.constructor.name}.${key}` message = message || 'this feature will be deprecated soon!' descriptor.value = () => { console.log(`${name} : ${message}`) original.apply(this, arguments) } return descriptor }
  28. import {readonly} from 'core-decorators' class Human { constructor(name) { this.name

    = name } @readonly speak() { console.log('Hi! My name is ' + this.name) } } core-decorators
  29. import {time} from 'core-decorators' class Human { constructor(name) { this.name

    = name } @time('speak') // Human.speak-0: 1.582ms speak() { console.log('Hi! My name is ' + this.name) } } core-decorators
  30. @type('mammal') class Human { constructor(name) { this.name = name console.log('I

    am' + this.name + ', a ' + this.type) } } /* class Dolphin class Crocodile class Fish */ class decorators
  31. @type('mammal') class Human { constructor(name) { this.name = name console.log('I

    am' + this.name + ', a ' + this.type) } } const type = value => target => { // add {type: value} to the target class } class decorators
  32. A higher-order component is a function that takes a component

    and returns a new (modified) component. class Label extends React.Component
  33. class Title extends React.Component { render () { return <div>hello

    {this.props.name}</div> } } /* <Post> <Title name="..."/> </Post> /*
  34. @loading('name') class Title extends React.Component { render () { return

    <div>hello {this.props.name}</div> } } /* <Post> <Title name="..."/> </Post> /* HOC
  35. @loading('name') class Title extends React.Component { render () { return

    <div>hello {this.props.name}</div> } } const loading = key => target => class extends React.Component { } HOC
  36. @loading('name') class Title extends React.Component { render () { return

    <div>hello {this.props.name}</div> } } const loading = key => Component => class extends React.Component { } HOC
  37. @loading('name') class Title extends React.Component { render () { return

    <div>hello {this.props.name}</div> } } const loading = key => Component => class extends React.Component { render () { if (this.props[key]) return <Component {...this.props} else return <div>loading...</div> } } HOC
  38. import {withProps} from 'recompose' @withProps({name: 'world'}) class Title extends React.Component

    { render () { return <div>hello {this.props.name}</div> } } recompose
  39. import {withHandlers, compose} from 'recompose' const handlers = withHandlers({ onClick:

    props => event => mixpanel.track('Clicked', props) }) recompose
  40. import {withHandlers, compose} from 'recompose' const handlers = withHandlers({ onClick:

    props => event => mixpanel.track('Clicked', props) }) const analytics = compose(handlers) recompose
  41. import {withHandlers, compose} from 'recompose' const handlers = withHandlers({ onClick:

    props => event => mixpanel.track('Clicked', props) }) const analytics = compose(handlers) @analytics class Title extends React.Component { render () { return <div>hello {this.props.label}</div> } } recompose
  42. import {onlyUpdateForKeys} from 'recompose' @onlyUpdateForKeys(['name']) class Title extends React.Component {

    render () { return <div>hello {this.props.name}</div> } } /* <Post> <Title {...props}/> </Post> /* recompose
  43. class Title extends React.Component { constructor () {} /* javascript

    constructor */ css () {} /* css constructor ? */ render () { return <div>hello {this.props.name}</div> } } rant/wish
  44. import css from 'css-constructor' class Title extends React.Component { constructor

    () {} @css` font-size: 16px; color: {this.props.colors}; &:hover {color: #FFF;} @media {max-width: 480px} {&: font-size: 18px;} ` render () { return <div>hello {this.props.name}</div> } } css-constructor
  45. @css(styles) = higher order function const css = styles =>

    (target, key, descriptor) => { } css-constructor
  46. @css(styles) = higher order function const css = styles =>

    (target, key, descriptor) => { const prettyCSS = process(styles) // fill props, media queries, etc. const cssClass = getUniqueClassName(prettyCSS) document.head.styles += {cssClass: prettyCSS} return componentWithClassName(cssClass) } css-constructor