You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React:组合式组件场景下,子组件如何向父组件传递数据?

在React组合式组件中实现SwitchGroup状态管理

完全可以用React Context来实现这种组合式组件的状态共享,把SwitchGroup的逻辑完全封装在内部,子Switch自动和Group通信,不用手动传递回调函数。下面是具体实现方案:

1. 创建上下文(Context)

首先定义一个上下文,用来在SwitchGroup和它的子Switch之间传递状态和更新方法:

import { createContext, useContext, useState, useId, useEffect, Children, isValidElement } from 'react';

const SwitchGroupContext = createContext(null);

2. 实现SwitchGroup组件

SwitchGroup负责维护组内所有Switch的状态,并处理“不能全关”的核心逻辑:

export function SwitchGroup({ children }) {
  // 存储每个Switch的状态:key为开关唯一ID,value为是否选中
  const [switchStates, setSwitchStates] = useState({});

  // 计算当前处于启用状态的开关数量
  const enabledCount = Object.values(switchStates).filter(checked => checked).length;

  // 更新单个开关状态的方法
  const updateSwitch = (id, newChecked) => {
    setSwitchStates(prev => {
      // 如果要关闭最后一个启用的开关,阻止更新
      if (!newChecked && enabledCount === 1) {
        return prev;
      }
      return { ...prev, [id]: newChecked };
    });
  };

  // 初始化子开关的状态:优先使用Switch传入的checked,默认启用
  useEffect(() => {
    const initialStates = {};
    Children.forEach(children, child => {
      if (isValidElement(child)) {
        const id = child.props.id || useId();
        initialStates[id] = child.props.checked ?? true;
      }
    });
    setSwitchStates(initialStates);
  }, [children]);

  return (
    <SwitchGroupContext.Provider value={{ switchStates, updateSwitch, enabledCount }}>
      {children}
    </SwitchGroupContext.Provider>
  );
}

3. 实现Switch组件

Switch组件消费上下文,自动获取状态和更新逻辑,无需手动传递回调:

export function Switch({ id: propsId, checked: propsChecked, ...rest }) {
  // 生成唯一ID,支持用户自定义ID
  const id = propsId || useId();
  const { switchStates, updateSwitch, enabledCount } = useContext(SwitchGroupContext);

  // 确定当前开关的选中状态:props传入的优先级最高
  const currentChecked = propsChecked ?? switchStates[id] ?? true;
  // 当仅剩一个启用开关时,禁用当前开关的关闭操作
  const isDisabled = enabledCount === 1 && currentChecked;

  const handleChange = (e) => {
    updateSwitch(id, e.target.checked);
  };

  return (
    <label style={{ display: 'block', margin: '8px 0' }}>
      <input
        type="checkbox"
        id={id}
        checked={currentChecked}
        onChange={handleChange}
        disabled={isDisabled}
        {...rest}
      />
      {rest.children}
    </label>
  );
}

4. 使用示例

现在你可以用完全组合式的写法使用组件,不用手动传递任何状态回调:

// 在任意组件中使用
function App() {
  return (
    <div>
      <h3>开关组示例</h3>
      <SwitchGroup>
        <Switch>功能A</Switch>
        <Switch checked={false}>功能B</Switch>
        <Switch>功能C</Switch>
      </SwitchGroup>
    </div>
  );
}

核心特性说明

  • 完全封装逻辑:所有“不能全关”的判断和状态管理都在SwitchGroup内部,外层组件无需关心。
  • 组合式写法:直接用SwitchGroup包裹Switch即可,不用手动传递onChange或状态。
  • 灵活性:支持Switch自定义初始状态、ID,也可以自动生成默认值。
  • 动态适配:如果动态添加/删除Switch,SwitchGroup会自动更新状态和启用计数。

内容的提问来源于stack exchange,提问作者lemming

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 09:34:04