WHAT - 受控组件和非受控组件

文章目录

场景:有一个react组件,他的功能是有一个title和Content,后者基于一个hidden的状态来控制。我现在希望这个组件内部支持toggle之外,父组件也可以去控制。怎么实现比较好?

这是一个非常经典的"受控 + 非受控组件"场景。

  1. 组件内部 有一个 hidden 状态,可以通过自身的 toggle 来控制显示/隐藏;
  2. 父组件 也可以通过传入 props 来控制 hidden 状态;
  3. 当父组件不传时,组件自行管理状态;当父组件传了时,组件跟随父组件状态变化。

推荐的实现方式是使用 "受控优先 + 非受控兜底" 模式。


子组件实现

ts 复制代码
import React, { useState, useEffect } from "react";

interface ToggleBoxProps {
  title: string;
  hidden?: boolean; // 受控
  defaultHidden?: boolean; // 非受控
  onToggle?: (nextHidden: boolean) => void;
}

const ToggleBox: React.FC<ToggleBoxProps> = ({
  title,
  hidden: controlledHidden,
  defaultHidden = false,
  onToggle,
  children
}) => {
  // 内部状态,仅当父组件不传 controlledHidden 时生效
  const [uncontrolledHidden, setUncontrolledHidden] = useState(defaultHidden);

  const isControlled = controlledHidden !== undefined;
  const effectiveHidden = isControlled ? controlledHidden : uncontrolledHidden;

  const handleToggle = () => {
    const next = !effectiveHidden;
    if (!isControlled) {
      setUncontrolledHidden(next);
    }
    onToggle?.(next);
  };

  return (
    <div style={{ border: "1px solid #ccc", padding: "8px" }}>
      <div
        style={{ cursor: "pointer", fontWeight: "bold" }}
        onClick={handleToggle}
      >
        {title} {effectiveHidden ? "▼" : "▲"}
      </div>
      {!effectiveHidden && <div>{children}</div>}
    </div>
  );
};

export default ToggleBox;

父组件使用方式

情况 1:非受控使用(自己内部管理)

ts 复制代码
export default function App() {
  return (
    <ToggleBox title="非受控组件">
      <p>这是一段内容,点击标题可以展开/收起</p>
    </ToggleBox>
  );
}

情况 2:受控使用(父组件控制)

ts 复制代码
import React, { useState } from "react";
import ToggleBox from "./ToggleBox";

export default function App() {
  const [hidden, setHidden] = useState(false);

  return (
    <>
      <button onClick={() => setHidden((prev) => !prev)}>
        父组件控制 {hidden ? "展开" : "收起"}
      </button>

      <ToggleBox
        title="受控组件"
        hidden={hidden}
        onToggle={(next) => setHidden(next)}
      >
        <p>这段内容跟随父组件变化</p>
      </ToggleBox>
    </>
  );
}

这样设计的好处

  • 保留组件内部交互能力(非受控)
  • 父组件也能随时接管控制(受控)
  • 受控和非受控不会冲突,通过 hidden 是否传入自动切换模式
  • 通过 onToggle 让父组件也能响应用户点击

如果你希望"父组件控制优先,但子组件点击也能同步状态",那 onToggle 就非常关键------它让子组件的行为能回传给父组件来同步状态。

相关推荐
空中湖18 分钟前
Spring AI Agent 编排:ReAct 模式 + 多 Agent 协作实战
人工智能·spring·react.js
吃糖的小孩32 分钟前
从只读页面到可控真实探针:我如何给 Owner Console 加手动诊断
前端
谷无姜32 分钟前
为什么你的性能优化无效?可能是"木桶效应"在作祟
前端·性能优化
雾非雾35 分钟前
《基于具身交互智能数字人技术:如何打造AI数字人宣讲平台"红厅智播”》
前端
Revolution611 小时前
一段 JavaScript 代码执行时,到底发生了什么
前端·javascript
智能起源1 小时前
关于元素层级过多,导致压祯的问题(使用winform或者WPF应用的webview组件嵌套网页时,动效卡顿问题)
前端
Old Uncle Tom2 小时前
银行用户画像 -- 金融目标与需求意图
前端·人工智能·金融
IT_陈寒2 小时前
Vue的响应式让我加班到凌晨3点,原来问题出在这
前端·人工智能·后端
东方小月2 小时前
从0开发一个 Coding Agent(一):前言
前端·人工智能·typescript