If someone uses one of our compound components outside the React.createContext
<ToggleContext.Provider />
, they will experience a confusing error. We could provide a default value for our context, but in our situation that doesn't make sense. Instead let's build a simple function component which does validation of our contextValue
that comes from the <ToggleContext.Consumer />
. That way we can provide a more helpful error message.
import React from 'react' import {Switch} from '../switch' const ToggleContext = React.createContext() function ToggleConsumer(props) { return ( <ToggleContext.Consumer {...props}> {context => { if (!context) { throw new Error( `Toggle compound components cannot be rendered outside the Toggle component`, ) } return props.children(context) }} </ToggleContext.Consumer> ) } class Toggle extends React.Component { static On = ({children}) => ( <ToggleConsumer> {({on}) => (on ? children : null)} </ToggleConsumer> ) static Off = ({children}) => ( <ToggleConsumer> {({on}) => (on ? null : children)} </ToggleConsumer> ) static Button = props => ( <ToggleConsumer> {({on, toggle}) => ( <Switch on={on} onClick={toggle} {...props} /> )} </ToggleConsumer> ) state = {on: false} toggle = () => this.setState( ({on}) => ({on: !on}), () => this.props.onToggle(this.state.on), ) render() { return ( <ToggleContext.Provider value={{on: this.state.on, toggle: this.toggle}} > {this.props.children} </ToggleContext.Provider> ) } } function Usage({ onToggle = (...args) => console.log('onToggle', ...args), }) { return ( <Toggle onToggle={onToggle}> <Toggle.On>The button is on</Toggle.On> <Toggle.Off>The button is off</Toggle.Off> <div> <Toggle.Button /> </div> </Toggle> ) } Usage.title = 'Flexible Compound Components' export {Toggle, Usage as default}