[React] Make Compound React Components Flexible

Our current compound component implementation is great, but it's limited in that users cannot render the structure they need. Let's allow the user to have more flexibility by using React context to share the implicit state to our child <Toggle/> components. We will walk through using React's official context API with React.createContext and use the given Provider and Consumer components to share state implicitly between our compound components giving our users the flexibility they need out of our component.

 

When we use compound component, we are also using React.Children.map:

    return React.Children.map(this.props.children, child => {
      return React.cloneElement(child, {
        on: this.state.on,
        toggle: this.toggle,
      })
    })

React.Children.map + this.props.children limits what compound compoment should found some structure, you can do:

  return (
    <Toggle onToggle={onToggle}>
      <Toggle.On>The button is on</Toggle.On>
      <Toggle.Button />
      <Toggle.Off>The button is off</Toggle.Off>
    </Toggle>
  )

 

But app will break if you do:

复制代码
  return (
    <Toggle onToggle={onToggle}>
      <Toggle.On>The button is on</Toggle.On>
      <Toggle.Button />
      <div>
         <Toggle.Off>The button is off</Toggle.Off>
      </div>
    </Toggle>
  )    
复制代码

Because this.props.children will looking for direct child inside <Toggle>, if we add <div> wrapper, it will break the structure, then code won't work.

 

So we need more flexable code, to achieve that we can use Context.

复制代码
// Flexible Compound Components with context

import React from 'react'
import {Switch} from '../switch'

const ToggleContext = React.createContext()

class Toggle extends React.Component {

  static On = ({children}) => (
    <ToggleContext.Consumer>
      {contextValue => (contextValue.on ? children : null)}
    </ToggleContext.Consumer>
  )
  static Off = ({children}) => (
    <ToggleContext.Consumer>
      {contextValue => (contextValue.on ? null : children)}
    </ToggleContext.Consumer>
  )
  static Button = props => (
    <ToggleContext.Consumer>
      {contextValue => (
        <Switch
          on={contextValue.on}
          onClick={contextValue.toggle}
          {...props}
        />
      )}
    </ToggleContext.Consumer>
  )
  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}
复制代码

 

posted @   Zhentiw  阅读(333)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2015-08-27 [React] React Fundamentals: Precompile JSX
点击右上角即可分享
微信分享提示