Skip to content

Instantly share code, notes, and snippets.

@vnglst
Last active February 1, 2018 08:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vnglst/6df41d29c286aa2a5590dbf7c0cb9a9a to your computer and use it in GitHub Desktop.
Save vnglst/6df41d29c286aa2a5590dbf7c0cb9a9a to your computer and use it in GitHub Desktop.
Egghead React Kent C. Dodds
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} />
)
}
class Toggle extends React.Component {
static On = ToggleOn
static Off = ToggleOff
static Button = ToggleButton
static defaultProps = {onToggle: () => {}}
state = {on: false}
toggle = () =>
this.setState(
({on}) => ({on: !on}),
() => this.props.onToggle(this.state.on),
)
render() {
const children = React.Children.map(
this.props.children,
child =>
React.cloneElement(child, {
on: this.state.on,
toggle: this.toggle,
}),
)
return <div>{children}</div>
}
}
function App() {
return (
<Toggle
onToggle={on => console.log('toggle', on)}
>
<Toggle.On>The button is on</Toggle.On>
<Toggle.Off>The button is off</Toggle.Off>
<Toggle.Button />
</Toggle>
)
}
const TOGGLE_CONTEXT = '__toggle__'
const ToggleOn = ({children, toggle: {on}}) => {
return on ? children : null
}
const ToggleOff = ({children, toggle: {on}}) => {
return on ? null : children
}
const ToggleButton = ({
toggle: {on, toggle},
...props
}) => {
return (
<Switch on={on} onClick={toggle} {...props} />
)
}
class Toggle extends React.Component {
static On = withToggle(ToggleOn)
static Off = withToggle(ToggleOff)
static Button = withToggle(ToggleButton)
static defaultProps = {onToggle: () => {}}
static childContextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired,
}
state = {on: false}
toggle = () =>
this.setState(
({on}) => ({on: !on}),
() => this.props.onToggle(this.state.on),
)
getChildContext() {
return {
[TOGGLE_CONTEXT]: {
on: this.state.on,
toggle: this.toggle,
},
}
}
render() {
return <div>{this.props.children}</div>
}
}
function withToggle(Component) {
function Wrapper(props, context) {
const toggleContext = context[TOGGLE_CONTEXT]
return (
<Component
{...props}
toggle={toggleContext}
/>
)
}
Wrapper.contextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired,
}
Wrapper.displayName = `withToggle(${Component.displayName ||
Component.name})`
return Wrapper
}
const MyToggle = ({toggle: {on, toggle}}) => (
<button onClick={toggle}>
{on ? 'on' : 'off'}
</button>
)
const MyToggleWrapper = withToggle(MyToggle)
function App() {
return (
<Toggle
onToggle={on => console.log('toggle', on)}
>
<Toggle.On>The button is on</Toggle.On>
<Toggle.Off>The button is off</Toggle.Off>
<Toggle.Button />
<hr />
<MyToggleWrapper />
</Toggle>
)
}
const TOGGLE_CONTEXT = '__toggle__'
const ToggleOn = ({children, toggle: {on}}) => {
return on ? children : null
}
const ToggleOff = ({children, toggle: {on}}) => {
return on ? null : children
}
const ToggleButton = ({
toggle: {on, toggle},
...props
}) => {
return (
<Switch on={on} onClick={toggle} {...props} />
)
}
class Toggle extends React.Component {
static On = withToggle(ToggleOn)
static Off = withToggle(ToggleOff)
static Button = withToggle(ToggleButton)
static defaultProps = {onToggle: () => {}}
static childContextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired,
}
state = {on: false}
toggle = () =>
this.setState(
({on}) => ({on: !on}),
() => this.props.onToggle(this.state.on),
)
getChildContext() {
return {
[TOGGLE_CONTEXT]: {
on: this.state.on,
toggle: this.toggle,
},
}
}
render() {
return <div>{this.props.children}</div>
}
}
function withToggle(Component) {
function Wrapper(
{innerRef, ...props},
context,
) {
const toggleContext = context[TOGGLE_CONTEXT]
return (
<Component
{...props}
ref={innerRef}
toggle={toggleContext}
/>
)
}
Wrapper.contextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired,
}
Wrapper.displayName = `withToggle(${Component.displayName ||
Component.name})`
return Wrapper
}
class MyToggle extends React.Component {
focus = () => this.button.focus()
render() {
const {toggle: {on, toggle}} = this.props
return (
<button
onClick={toggle}
ref={button => (this.button = button)}
>
{on ? 'on' : 'off'}
</button>
)
}
}
const MyToggleWrapper = withToggle(MyToggle)
class App extends React.Component {
render() {
return (
<Toggle
onToggle={on =>
on ? this.myToggle.focus() : null}
>
<Toggle.On>The button is on</Toggle.On>
<Toggle.Off>The button is off</Toggle.Off>
<Toggle.Button />
<hr />
<MyToggleWrapper
innerRef={myToggle =>
(this.myToggle = myToggle)}
/>
</Toggle>
)
}
}
const TOGGLE_CONTEXT = '__toggle__'
const ToggleOn = ({children, toggle: {on}}) => {
return on ? children : null
}
const ToggleOff = ({children, toggle: {on}}) => {
return on ? null : children
}
const ToggleButton = ({
toggle: {on, toggle},
...props
}) => {
return (
<Switch on={on} onClick={toggle} {...props} />
)
}
class Toggle extends React.Component {
static On = withToggle(ToggleOn)
static Off = withToggle(ToggleOff)
static Button = withToggle(ToggleButton)
static defaultProps = {onToggle: () => {}}
static childContextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired,
}
state = {on: false}
toggle = () =>
this.setState(
({on}) => ({on: !on}),
() => this.props.onToggle(this.state.on),
)
getChildContext() {
return {
[TOGGLE_CONTEXT]: {
on: this.state.on,
toggle: this.toggle,
},
}
}
render() {
return <div>{this.props.children}</div>
}
}
function withToggle(Component) {
function Wrapper(
{innerRef, ...props},
context,
) {
const toggleContext = context[TOGGLE_CONTEXT]
return (
<Component
{...props}
ref={innerRef}
toggle={toggleContext}
/>
)
}
Wrapper.contextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired,
}
Wrapper.displayName = `withToggle(${Component.displayName ||
Component.name})`
return Wrapper
}
class MyToggle extends React.Component {
focus = () => this.button.focus()
render() {
const {toggle: {on, toggle}} = this.props
return (
<button
onClick={toggle}
ref={button => (this.button = button)}
>
{on ? 'on' : 'off'}
</button>
)
}
}
const MyToggleWrapper = withToggle(MyToggle)
class App extends React.Component {
render() {
return (
<Toggle
onToggle={on =>
on ? this.myToggle.focus() : null}
>
<Toggle.On>The button is on</Toggle.On>
<Toggle.Off>The button is off</Toggle.Off>
<Toggle.Button />
<hr />
<MyToggleWrapper
innerRef={myToggle =>
(this.myToggle = myToggle)}
/>
</Toggle>
)
}
}
const TOGGLE_CONTEXT = '__toggle__'
const ToggleOn = ({children, toggle: {on}}) => {
return on ? children : null
}
const ToggleOff = ({children, toggle: {on}}) => {
return on ? null : children
}
const ToggleButton = ({
toggle: {on, toggle},
...props
}) => {
return (
<Switch on={on} onClick={toggle} {...props} />
)
}
class Toggle extends React.Component {
static On = withToggle(ToggleOn)
static Off = withToggle(ToggleOff)
static Button = withToggle(ToggleButton)
static defaultProps = {onToggle: () => {}}
static childContextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired,
}
state = {on: false}
toggle = () =>
this.setState(
({on}) => ({on: !on}),
() => this.props.onToggle(this.state.on),
)
getChildContext() {
return {
[TOGGLE_CONTEXT]: {
on: this.state.on,
toggle: this.toggle,
},
}
}
render() {
return <div>{this.props.children}</div>
}
}
function withToggle(Component) {
function Wrapper(
{innerRef, ...props},
context,
) {
const toggleContext = context[TOGGLE_CONTEXT]
return (
<Component
{...props}
ref={innerRef}
toggle={toggleContext}
/>
)
}
Wrapper.contextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired,
}
Wrapper.displayName = `withToggle(${Component.displayName ||
Component.name})`
return Wrapper
}
class MyToggle extends React.Component {
focus = () => this.button.focus()
render() {
const {toggle: {on, toggle}} = this.props
return (
<button
onClick={toggle}
ref={button => (this.button = button)}
>
{on ? 'on' : 'off'}
</button>
)
}
}
const MyToggleWrapper = withToggle(MyToggle)
class App extends React.Component {
render() {
return (
<Toggle
onToggle={on =>
on ? this.myToggle.focus() : null}
>
<Toggle.On>The button is on</Toggle.On>
<Toggle.Off>The button is off</Toggle.Off>
<Toggle.Button />
<hr />
<MyToggleWrapper
innerRef={myToggle =>
(this.myToggle = myToggle)}
/>
</Toggle>
)
}
}
const TOGGLE_CONTEXT = '__toggle__'
const ToggleOn = ({children, toggle: {on}}) => {
return on ? children : null
}
const ToggleOff = ({children, toggle: {on}}) => {
return on ? null : children
}
const ToggleButton = ({
toggle: {on, toggle},
...props
}) => {
return (
<Switch on={on} onClick={toggle} {...props} />
)
}
class Toggle extends React.Component {
static On = withToggle(ToggleOn)
static Off = withToggle(ToggleOff)
static Button = withToggle(ToggleButton)
static defaultProps = {onToggle: () => {}}
static childContextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired,
}
state = {on: false}
toggle = () =>
this.setState(
({on}) => ({on: !on}),
() => this.props.onToggle(this.state.on),
)
getChildContext() {
return {
[TOGGLE_CONTEXT]: {
on: this.state.on,
toggle: this.toggle,
},
}
}
render() {
return <div>{this.props.children}</div>
}
}
function withToggle(Component) {
function Wrapper(
{innerRef, ...props},
context,
) {
const toggleContext = context[TOGGLE_CONTEXT]
return (
<Component
{...props}
ref={innerRef}
toggle={toggleContext}
/>
)
}
Wrapper.contextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired,
}
Wrapper.displayName = `withToggle(${Component.displayName ||
Component.name})`
Wrapper.WrappedComponent = Component
return Wrapper
}
const MyToggle = ({toggle: {on, toggle}}) => (
<button onClick={toggle}>
{on ? 'on' : 'off'}
</button>
)
const MyToggleWrapper = withToggle(MyToggle)
function test() {
const div = document.createElement('div')
document.body.appendChild(div)
const toggle = () => (toggle.called = true)
ReactDOM.render(
<MyToggleWrapper.WrappedComponent
toggle={{on: true, toggle}}
/>,
div,
)
if (!div.innerHTML.includes('on')) {
throw new Error(
`Contents are wrong: ${div.innerHTML}`,
)
}
const button = div.getElementsByTagName(
'button',
)[0]
button.click()
if (!toggle.called) {
throw new Error('toggle not called!')
}
}
test()
function App() {
return (
<Toggle
onToggle={on => console.log('toggle', on)}
>
<Toggle.On>The button is on</Toggle.On>
<Toggle.Off>The button is off</Toggle.Off>
<Toggle.Button />
<hr />
<MyToggleWrapper />
</Toggle>
)
}
const TOGGLE_CONTEXT = '__toggle__'
const ToggleOn = ({children, toggle: {on}}) => {
return on ? children : null
}
const ToggleOff = ({children, toggle: {on}}) => {
return on ? null : children
}
const ToggleButton = ({
toggle: {on, toggle},
...props
}) => {
return (
<Switch on={on} onClick={toggle} {...props} />
)
}
class Toggle extends React.Component {
static On = withToggle(ToggleOn)
static Off = withToggle(ToggleOff)
static Button = withToggle(ToggleButton)
static defaultProps = {onToggle: () => {}}
static childContextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired,
}
state = {on: false}
toggle = () =>
this.setState(
({on}) => ({on: !on}),
() => this.props.onToggle(this.state.on),
)
getChildContext() {
return {
[TOGGLE_CONTEXT]: {
on: this.state.on,
toggle: this.toggle,
},
}
}
render() {
return <div>{this.props.children}</div>
}
}
function withToggle(Component) {
function Wrapper(
{innerRef, ...props},
context,
) {
const toggleContext = context[TOGGLE_CONTEXT]
return (
<Component
{...props}
ref={innerRef}
toggle={toggleContext}
/>
)
}
Wrapper.contextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired,
}
Wrapper.displayName = `withToggle(${Component.displayName ||
Component.name})`
Wrapper.WrappedComponent = Component
return hoistNonReactStatics(Wrapper, Component)
}
class MyToggle extends React.Component {
static ToggleMessage = withToggle(
({toggle: {on}}) =>
on
? 'Warning: The button is toggled on'
: null,
)
render() {
const {toggle: {on, toggle}} = this.props
return (
<button onClick={toggle}>
{on ? 'on' : 'off'}
</button>
)
}
}
const MyToggleWrapper = withToggle(MyToggle)
function App() {
return (
<Toggle
onToggle={on => console.log('toggle', on)}
>
<Toggle.On>The button is on</Toggle.On>
<Toggle.Off>The button is off</Toggle.Off>
<Toggle.Button />
<hr />
<MyToggleWrapper />
<hr />
<MyToggleWrapper.ToggleMessage />
</Toggle>
)
}
const TOGGLE_CONTEXT = '__toggle__'
function ToggleOn({children}, context) {
const {on} = context[TOGGLE_CONTEXT]
return on ? children : null
}
ToggleOn.contextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired,
}
function ToggleOff({children}, context) {
const {on} = context[TOGGLE_CONTEXT]
return on ? null : children
}
ToggleOff.contextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired,
}
function ToggleButton(props, context) {
const {on, toggle} = context[TOGGLE_CONTEXT]
return (
<Switch on={on} onClick={toggle} {...props} />
)
}
ToggleButton.contextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired,
}
class Toggle extends React.Component {
static On = ToggleOn
static Off = ToggleOff
static Button = ToggleButton
static defaultProps = {onToggle: () => {}}
static childContextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired,
}
state = {on: false}
toggle = () =>
this.setState(
({on}) => ({on: !on}),
() => this.props.onToggle(this.state.on),
)
getChildContext() {
return {
[TOGGLE_CONTEXT]: {
on: this.state.on,
toggle: this.toggle,
},
}
}
render() {
return <div>{this.props.children}</div>
}
}
function App() {
return (
<Toggle
onToggle={on => console.log('toggle', on)}
>
<Toggle.On>The button is on</Toggle.On>
<Toggle.Off>The button is off</Toggle.Off>
<div>
<Toggle.Button />
</div>
</Toggle>
)
}
const TOGGLE_CONTEXT = '__toggle__'
const ToggleOn = withToggle(({children, on}) => {
return on ? children : null
})
const ToggleOff = withToggle(({children, on}) => {
return on ? null : children
})
const ToggleButton = withToggle(
({on, toggle, ...props}) => {
return (
<Switch
on={on}
onClick={toggle}
{...props}
/>
)
},
)
class Toggle extends React.Component {
static On = ToggleOn
static Off = ToggleOff
static Button = ToggleButton
static defaultProps = {onToggle: () => {}}
static childContextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired,
}
state = {on: false}
toggle = () =>
this.setState(
({on}) => ({on: !on}),
() => this.props.onToggle(this.state.on),
)
getChildContext() {
return {
[TOGGLE_CONTEXT]: {
on: this.state.on,
toggle: this.toggle,
},
}
}
render() {
return <div>{this.props.children}</div>
}
}
function withToggle(Component) {
function Wrapper(props, context) {
const toggleContext = context[TOGGLE_CONTEXT]
return (
<Component {...toggleContext} {...props} />
)
}
Wrapper.contextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired,
}
return Wrapper
}
const MyToggle = withToggle(({on, toggle}) => (
<button onClick={toggle}>
{on ? 'on' : 'off'}
</button>
))
function App() {
return (
<Toggle
onToggle={on => console.log('toggle', on)}
>
<Toggle.On>The button is on</Toggle.On>
<Toggle.Off>The button is off</Toggle.Off>
<Toggle.Button />
<hr />
<MyToggle />
</Toggle>
)
}
const TOGGLE_CONTEXT = '__toggle__'
const ToggleOn = ({children, toggle: {on}}) => {
return on ? children : null
}
const ToggleOff = ({children, toggle: {on}}) => {
return on ? null : children
}
const ToggleButton = ({
toggle: {on, toggle},
...props
}) => {
return (
<Switch on={on} onClick={toggle} {...props} />
)
}
class Toggle extends React.Component {
static On = withToggle(ToggleOn)
static Off = withToggle(ToggleOff)
static Button = withToggle(ToggleButton)
static defaultProps = {onToggle: () => {}}
static childContextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired,
}
state = {on: false}
toggle = () =>
this.setState(
({on}) => ({on: !on}),
() => this.props.onToggle(this.state.on),
)
getChildContext() {
return {
[TOGGLE_CONTEXT]: {
on: this.state.on,
toggle: this.toggle,
},
}
}
render() {
return <div>{this.props.children}</div>
}
}
function withToggle(Component) {
function Wrapper(
{innerRef, ...props},
context,
) {
const toggleContext = context[TOGGLE_CONTEXT]
return (
<Component
{...props}
ref={innerRef}
toggle={toggleContext}
/>
)
}
Wrapper.contextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired,
}
Wrapper.displayName = `withToggle(${Component.displayName ||
Component.name})`
return Wrapper
}
class MyToggle extends React.Component {
focus = () => this.button.focus()
render() {
const {toggle: {on, toggle}} = this.props
return (
<button
onClick={toggle}
ref={button => (this.button = button)}
>
{on ? 'on' : 'off'}
</button>
)
}
}
const MyToggleWrapper = withToggle(MyToggle)
class App extends React.Component {
render() {
return (
<Toggle
onToggle={on =>
on ? this.myToggle.focus() : null}
>
<Toggle.On>The button is on</Toggle.On>
<Toggle.Off>The button is off</Toggle.Off>
<Toggle.Button />
<hr />
<MyToggleWrapper
innerRef={myToggle =>
(this.myToggle = myToggle)}
/>
</Toggle>
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment