Skip to content

Instantly share code, notes, and snippets.

@michaelrambeau
Last active April 12, 2018 07:54
Show Gist options
  • Save michaelrambeau/8aea4945114b90053939191925768287 to your computer and use it in GitHub Desktop.
Save michaelrambeau/8aea4945114b90053939191925768287 to your computer and use it in GitHub Desktop.
Advanced React Patterns V2 Workshop from https://github.com/kentcdodds/advanced-react-patterns-v2
// Compound Components
import React from 'react'
import {Switch} from '../switch'
class Toggle extends React.Component {
// you can create function components as static properties!
// for example:
// static Candy = (props) => <div>CANDY! {props.children}</div>
// Then that could be used like: <Toggle.Candy />
// This is handy because it makes the relationship between the
// parent Toggle component and the child Candy component more explicit
// 🐨 You'll need to create three such components here: On, Off, and Button
// The button will be responsible for rendering the <Switch /> (with the right pros)
state = {on: false}
static On = ({on, children}) => on ? children : null
static Off = ({on, children}) => on ? null : children
static Button = ({on, toggle, ...props}) => <Switch on={on} onClick={toggle} {...props} />
toggle = () =>
this.setState(
({on}) => ({on: !on}),
() => this.props.onToggle(this.state.on),
)
render() {
// we're trying to let people render the components they want within the Toggle component.
// But the On, Off, and Button components will need access to the internal `on` state as
// well as the internal `toggle` function for them to work properly. So here we can
// take all this.props.children and make a copy of them that has those props.
//
// To do this, you can use:
// 1. React.Children.map: https://reactjs.org/docs/react-api.html#reactchildrenmap
// 2. React.cloneElement: https://reactjs.org/docs/react-api.html#cloneelement
//
// 🐨 you'll want to completely replace the code below with the above logic.
return React.Children.map(this.props.children, child =>
React.cloneElement(child, {
on: this.state.on,
toggle: this.toggle,
}),
)
}
}
// Don't make changes to the Usage component. It's here to show you how your
// component is intended to be used and is used in the tests.
// You can make all the tests pass by updating the Toggle component.
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>
<Toggle.Button />
</Toggle>
)
}
export {Toggle, Usage as default}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment