To show how to write React components in a functional way, let’s assume we have to build a list of Presidents. Clicking on a list item would highlight that item.

We’ll be using the following libraries:

The following functional concepts and functors/patterns are used:

  • Curry
  • Compose
  • Lenses
  • Maybe

First let’s just start with a very basic implementation. Just a list, no clicking on item, no highlight. Just a plain list and the data is assumed to be perfect, i.e. no null whatsoever:

See the Pen OVpYjZ by kevinle (@kevinle) on CodePen.

The function functionalRender is as pure as you can get:

var functionalRender = (context, props, state) => {

var L = Lenses.makeLenses(['className', 'firstName', 'lastName'])

var buildJsx = x => <a key={x.id} href="#" className={x.className}>{x.firstName} {x.lastName}</a>

var buildCompose = R.compose(
buildJsx
,Lenses.set(L.className, 'collection-item')
,Lenses.over(L.firstName, R.toUpper)
,Lenses.over(L.lastName, R.toUpper)
);

return R.map(buildCompose, props.data)
}

Next assume, the data can potentially contain null values, but of course we don’t want to crash. So we’ll be using Maybe functors:

This is the result.

See the Pen dovEzv by kevinle (@kevinle) on CodePen.

The differences with the previous version are: we add the Maybe functor, an fmap function and curry it. All this so we can create a safeCapitalize, and the use it the Lenses.over

var functionalRender = (context, props, state) => {
var _Maybe = function(val) {
this.val = val
}

_Maybe.prototype.map = function(f) {
return this.val ? Maybe(f(this.val)) : Maybe(this.val)
}

var Maybe = x => new _Maybe(x)

var fmap = R.curry((f, mappable) => mappable.map(f))

var safeCapitalize = R.compose(fmap(R.toUpper), Maybe)


var L = Lenses.makeLenses(['className', 'firstName', 'lastName'])

var buildJsx = x => <a key={x.id} href="#" className={x.className}>{x.firstName} {x.lastName}</a>

var buildCompose = R.compose(
buildJsx
,Lenses.set(L.className, 'collection-item')
,Lenses.over(L.firstName, safeCapitalize)
,Lenses.over(L.lastName, safeCapitalize)
)

return R.map(buildCompose, props.data)
}

And finally, we add the ability to click on a list item and here’s the complete implementation:

See the Pen WbLRBo by kevinle (@kevinle) on CodePen.

When you look at the code below, pay attention to the click handler and the className which are the only 2 differences from the version above:

var functionalRender = (context, props, state) => {
var _Maybe = function(val) {
this.val = val
}

_Maybe.prototype.map = function(f) {
return this.val ? Maybe(f(this.val)) : Maybe(this.val)
}

var Maybe = x => new _Maybe(x)


var L = Lenses.makeLenses(['className', 'firstName', 'lastName'])

var isSelected = R.eq(state.selectedItem)
var self = x => { return () => { return x } }
var getClassName = R.ifElse(isSelected, self('collection-item active'), self('collection-item'))

var clickHandler = context.handleClick

var fmap = R.curry((f, mappable) => mappable.map(f))


var safeCapitalize = R.compose(fmap(R.toUpper), Maybe)

var buildJsx = x => <a key={x.id} href="#" onClick={clickHandler.bind(context, x.id)} className={x.className(x.id)}>{x.firstName} {x.lastName}</a>

var buildCompose = R.compose(
buildJsx
,Lenses.set(L.className, getClassName)
,Lenses.over(L.firstName, safeCapitalize)
,Lenses.over(L.lastName, safeCapitalize)
)

return R.map(buildCompose, props.data)
}