Skip to content

Instantly share code, notes, and snippets.

@busypeoples
Last active October 3, 2017 05:00
Show Gist options
  • Save busypeoples/f8e72da3c8a91c6ea4f1d7e9dde37072 to your computer and use it in GitHub Desktop.
Save busypeoples/f8e72da3c8a91c6ea4f1d7e9dde37072 to your computer and use it in GitHub Desktop.
setSateHigherOrderComponent for combining stateless functions with setState functions on the fly.

SetState React HigherOrderComponent

Why?

If you want to write stateless functions in React and need to combine a number of setState functions to that stateless function. Enables to compose a number of functions expecting state and props. This enables to reuse functions when needed and eases testing those functions (as they are standalone and decoupled from React.

Example

// counter.js

import React, {Component} from 'react'
import setStateHigherOrderComponent from './HigherOrderComponents'

// some set state function...
const Inc = () => (state, {step}) =>
  ({count: state.count + step})

const Dec = () => (state, {step}) => 
  ({count: state.count - step})

// some stateless function
const SomeStatelessFunction = ({count, inc, dec, ...rest}) => {
  return (
    <div>
      Count: {count}
      <button onClick={() => inc()}>Inc</button>
      <button onClick={() => dec()}>Dec</button>
    </div>
  )
}

export default setStateHigherOrderComponent({inc: Inc, dec: Dec}, SomeStatelessFunction)

Now you can use the Counter and define the initialState as needed.

import React from 'react'
import {render} from 'react-dom'
import CreateCounter from './Counter'

const CounterA = CreateCounter({count: 0})
const CounterB = CreateCounter({count: 10})
const CounterC = CreateCounter({count: 20})

render(<div>
  <CounterA step={1} />
  <CounterB step={2} />
  <CounterC step={3} />
</div>, document.getElementById('app'))

More

You can choose to switchout Ramda with another library, also you can remove the currying and adapt as needed. This is just a reference implementation.

Demo

Check the demo

Feedback

Twitter

import React from 'react'
import hoistNonReactStatics from 'hoist-non-react-statics'
import { curry, map } from 'ramda'
const setStateHigherOrderComponent = curry((setStateFns, WrappedComponent, initialState) => {
class HigherOrderComponent extends React.Component {
constructor(props) {
super(props)
this.state = initialState
this.fns = map(fn => (...args) => {
this.setState(fn(...args))
}, setStateFns)
}
render() {
const props = {...this.fns, ...this.props, ...this.state}
return React.createElement(WrappedComponent, {...props})
}
}
HigherOrderComponent.displayName =
`SetStateHigherOrderComponent_(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`
return hoistNonReactStatics(HigherOrderComponent, WrappedComponent)
})
export default setStateHigherOrderComponent
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment