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

React中useEffect同步defaultValue是否为反模式?如何简化代码?

问题:简化Toggle标签页组件代码,避免React反模式

我写了一个接收defaultValue的Toggle标签页组件,目前用useState把value初始化为defaultValue,又用useEffect监听defaultValue的变化来更新value,但我觉得这属于React反模式,请问怎么简化这段组件代码?

我的组件实现代码:

const Toggle = ({
  defaultValue,
  leftItem,
  rightItem,
  onValueChange,
  ...props
}) => {
  const [value, setValue] = useState(defaultValue);

  useEffect(() => {
    setValue(defaultValue);
  }, [defaultValue]);

  return (
    <div {...props}>
      <ToggleGroup
        type="single"
        value={value}
        onValueChange={(value) => {
          if (value) {
            setValue(value);
          }
        }}
      >
        <ToggleGroupItem value={leftItem.value}>
          {leftItem.label}
        </ToggleGroupItem>
        <ToggleGroupItem value={rightItem.value}>
          {rightItem.label}
        </ToggleGroupItem>
      </ToggleGroup>
    </div>
  );
};
解决方案

你现在的写法确实属于React里的反模式——用useEffect同步props到state完全没必要,我们可以通过区分受控/非受控组件的逻辑来优化:

核心优化点

  1. 你的组件现在是非受控模式(用defaultValue初始化状态),这种模式下不需要监听defaultValue的变化,因为defaultValue只负责提供初始值,后续状态由组件内部维护;
  2. 状态变化时要记得调用onValueChange,把新值同步给父组件,避免状态割裂;
  3. 把零散的回调逻辑抽成独立函数,代码更清晰。

优化后的代码

const Toggle = ({
  defaultValue,
  leftItem,
  rightItem,
  onValueChange,
  ...props
}) => {
  // 直接用defaultValue初始化内部state,无需额外监听
  const [value, setValue] = useState(defaultValue);

  const handleValueChange = (newValue) => {
    if (newValue) {
      setValue(newValue);
      // 调用父组件传入的回调,同步状态变化
      onValueChange?.(newValue);
    }
  };

  return (
    <div {...props}>
      <ToggleGroup
        type="single"
        value={value}
        onValueChange={handleValueChange}
      >
        <ToggleGroupItem value={leftItem.value}>
          {leftItem.label}
        </ToggleGroupItem>
        <ToggleGroupItem value={rightItem.value}>
          {rightItem.label}
        </ToggleGroupItem>
      </ToggleGroup>
    </div>
  );
};

进阶:支持受控模式

如果后续需要让组件同时支持受控模式(由父组件传入value并控制状态),可以调整成如下写法,兼容两种模式:

const Toggle = ({
  defaultValue,
  value: controlledValue, // 受控模式的外部value
  leftItem,
  rightItem,
  onValueChange,
  ...props
}) => {
  // 区分受控/非受控:外部传了value就用外部的,否则用内部state
  const [internalValue, setInternalValue] = useState(defaultValue);
  const currentValue = controlledValue !== undefined ? controlledValue : internalValue;

  const handleValueChange = (newValue) => {
    if (newValue) {
      // 受控模式下不更新内部state,直接触发回调让父组件处理
      if (controlledValue === undefined) {
        setInternalValue(newValue);
      }
      onValueChange?.(newValue);
    }
  };

  return (
    <div {...props}>
      <ToggleGroup
        type="single"
        value={currentValue}
        onValueChange={handleValueChange}
      >
        <ToggleGroupItem value={leftItem.value}>
          {leftItem.label}
        </ToggleGroupItem>
        <ToggleGroupItem value={rightItem.value}>
          {rightItem.label}
        </ToggleGroupItem>
      </ToggleGroup>
    </div>
  );
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 02:20:36