From the blog

Elegant React Component APIs with Functions as Children

react

We can develop some pretty elegant React Component APIs using functions as children in React Components. Take for example a Dropdown component. If we want it to be flexible by leaving the DOM structure up to the user, we would need some way to designate toggler elements of the Dropdown. One way is with the data-toggle attribute:

Open

However, this will require manually setting up event listeners on real DOM nodes, for example, the componentDidMount method on this component might look something like this:

componentDidMount() {
  const togglers = ReactDOM
    .findDOMNode(this)
    .querySelectorAll('[data-toggle]');
  Array.prototype.forEach.call(togglers, toggler => {
    toggler.addEventListener('click', this.toggle);
  });
},

A more elegant solution is to expose the component’s toggle method to its children by using a function as a child:

  {toggle =>

Open

 

}


This way, we’re using React’s event system instead of raw DOM events, and we wouldn’t need to implement componentDidMount at all.
When toggle is called, the opened CSS class will be toggled on the div element. In other words, the component would generate DOM that looks like this:

 

and when the toggle function is called, the opened class is added to the element:

 

The implementation of this Dropdown component looks like this:

const cx = require('classnames');
const enhanceWithClickOutside = require('react-click-outside');
const React = require('react');
const Dropdown = React.createClass({
  getInitialState() {
    return {
      opened: false,
    };
  },
  handleClick(e) {
    // Close dropdown when clicked on a menu item
    if (this.state.opened && e.target.tagName === 'A') {
      this.setState({ opened: false });
    }
  },
  handleClickOutside(e) {
    if (!this.state.opened) return;
    this.setState({ opened: false });
  },
  toggle() {
    this.setState({ opened: !this.state.opened });
  },
  render() {
    const child = this.props.children(this.toggle);
    return React.cloneElement(child, {
      className: cx(
        child.props.className,
        'dropdown',
        this.state.opened && 'opened'
      ),
      onClick: this.handleClick,
    });
  },
});
module.exports = enhanceWithClickOutside(Dropdown);

this.props.children is the function child of the Dropdown component, and it is called with the instance’s toggle method. This returns a React Element, the div, which we clone to add the dropdown and opened css classes.
A discussion of this pattern and other real world use cases can be found here.

Related articles

Big Compute Podcast: Optisys – Innovation in Antenna Design

In this Big Compute Podcast episode, Gabriel Broner hosts Mike Hollenbeck, founder and CTO at Optisys. Optisys uses HPC in the cloud and 3D printing to design customized antennas which are smaller, lighter and higher performing than traditional antennas.  […]

read more »

The Curious Case of the Windows HTTP Proxy

The web is the preferred delivery mechanism for most applications these days but there are scenarios where you might want to build a CLI or desktop application for your customers to use. However, once you leave the cozy confines of […]

read more »