[React] Prevent Unnecessary Rerenders of Compound Components using React Context

Due to the way that React Context Providers work, our current implementation re-renders all our compound component consumers with every render of the <Toggle /> which could lead to unnecessary re-renders. Let's fix that by ensuring that the value prop we pass to the <ToggleContext.Provider /> is only changed when the state changes.react

 

// Flexible Compound Components with context // This allows you to avoid unecessary rerenders
 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>
 ) // The reason we had to move `toggle` above `state` is because
  // in our `state` initialization we're _using_ `this.toggle`. So
  // if `this.toggle` is not defined before state is initialized, then
  // `state.toggle` will be undefined.
  toggle = () =>
    this.setState( ({on}) => ({on: !on}), () => this.props.onToggle(this.state.on), ) state = {on: false, toggle: this.toggle} render() { return ( <ToggleContext.Provider value={this.state}> {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}
相關文章
相關標籤/搜索