Share Code in React

Objective

<Code/> reuse

Credit

  • Michael Jackson
import React from 'react'
import createReactClass from 'create-react-class'
import styles from './styles'

const App = createReactClass({
  getInitialState () {
    return {
      x: 0,
      y: 0
    }
  },

  handleMouseMove ({ clientX, clientY }) {
    this.setState({
      x: clientX,
      y: clientY
    })
  },

  render () {
    const { x, y } = this.state
    return (
      <div style={styles.container} onMouseMove={this.handleMouseMove}>
        <h1>
          The mouse position is ({x}, {y})
        </h1>
      </div>
    )
  }
})

export default App

3 Patterns

Mixins

import React from 'react'
import createReactClass from 'create-react-class'
import styles from './styles'

const MouseMixin = {
  getInitialState () {
    return {
      x: 0,
      y: 0
    }
  },

  handleMouseMove ({ clientX, clientY }) {
    this.setState({
      x: clientX,
      y: clientY
    })
  }
}
const App = createReactClass({
  mixins: [MouseMixin],
  render () {
    const { x, y } = this.state
    return (
      <div style={styles.container} onMouseMove={this.handleMouseMove}>
        <h1>
          The mouse position is ({x}, {y})
        </h1>
      </div>
    )
  }
})

export default App

Mixins is Harmful

  • Not support ES6 class
    (since v0.13)
  • Who give me the states
  • Naming collisions

HOCs

Higher Order Function

const add = (x, y) => x + y

const createAdder = a => b => add(a, b)

const add10 = createAdder(10)

console.log(add10(2))

(gist by Sebastian in 2015)

import React, { PureComponent } from 'react'
import styles from './styles'

const withMouse = WrappedComponent =>
  class extends PureComponent {
    state = {
      x: 0,
      y: 0
    }
    handleMouseMove = ({ clientX, clientY }) => {
      this.setState({
        x: clientX,
        y: clientY
      })
    }
    render () {
      return (
        <div onMouseMove={this.handleMouseMove}>
          <WrappedComponent mouse={this.state} {...this.props} />
        </div>
      )
    }
  }

class App extends PureComponent {
  render () {
    const { message, mouse } = this.props
    const { x, y } = mouse
    return (
      <div style={styles.container}>
        <h1>
          The mouse position is ({x}, {y}). The message is {message}
        </h1>
      </div>
    )
  }
}
export default withMouse(App)

HOC

  • Favour ES6
  • Who give me the props?
  • Name clashes, pollute props namespace
  • Static composition
  • Consumer need to know the props name

Render Props

  • Render callback
  • FaCC
  • Add to Doc recently
import React, { PureComponent } from 'react'
import styles from './styles'

class Mouse extends PureComponent {
  state = { x: 0, y: 0 }

  handleMouseMove = ({ clientX, clientY }) => {
    this.setState({
      x: clientX,
      y: clientY
    })
  }
  render () {
    return (
      <div onMouseMove={this.handleMouseMove}>
        {this.props.children(this.state)}
      </div>
    )
  }
}

class App extends PureComponent {
  render () {
    const { message } = this.props
    return (
      <Mouse>
        {({ x, y }) =>
          (
            <div style={styles.container}>
            <h1>
              The mouse position is ({x}, {y}). The message is {message}
            </h1>
          </div>
          )
        }
      </Mouse>
    )
  }
}

export default App

Render Props Downside

  • Data only available in render function
  • Be careful not to create new function in render()
  • Not composable

Summary

Mixin HOC Render Props
ES6 Class πŸ™…β€β™‚οΈ πŸ‘Œ πŸ‘Œ
Where the data come from? πŸ€” πŸ€” Function arguments
Name clashes? πŸ’₯ πŸ’₯ 😊
Name awareness Need Need As how I name the argΒ 
Data availability Entire class Entire class Render function only
Composition Static Static Dynamic
Functional πŸ™…β€β™‚οΈ 😎 πŸ™…β€β™‚οΈ

Q & A

References

Share Code in React

By Ivan Ha

Share Code in React

Discuss 3 code sharing patterns in React, namely mixins, higher-order components (HOC) and render props.

  • 302