Last active
January 7, 2022 16:55
-
-
Save Neo42/2914d86f2b50272e98546994eb8f24bf to your computer and use it in GitHub Desktop.
React Patterns: Compound Components
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Compound Components w/ `React.Children.map` & `React.cloneElement` | |
import * as React from 'react' | |
import {Switch} from '../switch' | |
function Toggle({children}) { | |
const [on, setOn] = React.useState(false) | |
const toggle = () => setOn(!on) | |
return React.Children.map(children, child => | |
// tell if a child is a built-in DOM component | |
typeof child.type === 'string' | |
? child | |
: React.cloneElement(child, {on, toggle}), | |
) | |
} | |
function ToggleOn({on, children}) { | |
return on ? children : null | |
} | |
function ToggleOff({on, children}) { | |
return on ? null : children | |
} | |
function ToggleButton({on, toggle, ...props}) { | |
return <Switch on={on} onClick={toggle} {...props} /> | |
} | |
function App() { | |
return ( | |
<div> | |
<Toggle> | |
<ToggleOn>The button is on</ToggleOn> | |
<ToggleOff>The button is off</ToggleOff> | |
<span>Hello</span> | |
<ToggleButton /> | |
</Toggle> | |
</div> | |
) | |
} | |
// --------------------------------------------------------- | |
// Flexible Compound Components w/ React Context (without location limits on children) | |
const ToggleContext = React.createContext() | |
function Toggle({children}) { | |
const [on, setOn] = React.useState(false) | |
const toggle = () => setOn(!on) | |
// remember to forward `children` prop to render them | |
return <ToggleContext.Provider value={{on, toggle}} children={children} /> | |
} | |
function ToggleOn({children}) { | |
const {on} = React.useContext(ToggleContext) | |
return on ? children : null | |
} | |
function ToggleOff({children}) { | |
const {on} = React.useContext(ToggleContext) | |
return on ? null : children | |
} | |
function ToggleButton(props) { | |
const {on, toggle} = React.useContext(ToggleContext) | |
return <Switch on={on} onClick={toggle} {...props} /> | |
} | |
function App() { | |
return ( | |
<div> | |
<Toggle> | |
<ToggleOn>The button is on</ToggleOn> | |
<ToggleOff>The button is off</ToggleOff> | |
<div> | |
<ToggleButton /> // one level deeper, but still works because of Context | |
</div> | |
</Toggle> | |
</div> | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment