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 就非常关键------它让子组件的行为能回传给父组件来同步状态。

相关推荐
冴羽17 小时前
2025 年 HTML 年度调查报告公布!好多不知道!
前端·javascript·html
Apifox17 小时前
Apifox CLI + Claude Skills:将接口自动化测试融入研发工作流
前端·后端·测试
wszy180917 小时前
rn_for_openharmony_空状态与加载状态:别让用户对着白屏发呆
android·javascript·react native·react.js·harmonyos
程序员Agions18 小时前
别再只会 console.log 了!这 15 个 Console 调试技巧,让你的 Debug 效率翻倍
前端·javascript
我的div丢了肿么办18 小时前
vue使用h函数封装dialog组件,以命令的形式使用dialog组件
前端·javascript·vue.js
UIUV18 小时前
Git 提交规范与全栈AI驱动开发实战:从基础到高级应用
前端·javascript·后端
NEXT0618 小时前
那个写 width: 33.33% 的前端,终于被 flex: 1 拯救了
前端·css
NEXT0618 小时前
前端即导演:用纯 CSS3 原力复刻《星球大战》经典开场
前端·css