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

相关推荐
ZC跨境爬虫3 小时前
跟着 MDN 学 HTML day_9:(信件语义标记)
前端·css·笔记·ui·html
前端老石人3 小时前
HTML 字符引用完全指南
开发语言·前端·html
matlab_xiaowang3 小时前
Redux 入门:JavaScript 可预测状态管理库
开发语言·javascript·其他·ecmascript
幼儿园技术家3 小时前
前端如何设计权限系统(RBAC / ABAC)?
前端
前端摸鱼匠5 小时前
Vue 3 的v-bind合并行为:讲解v-bind与普通属性合并的规则
前端·javascript·vue.js·前端框架·ecmascript
REDcker5 小时前
浏览器端Web程序性能分析与优化实战 DevTools指标与工程清单
开发语言·前端·javascript·vue·ecmascript·php·js
donecoding7 小时前
一个 sudo 引发的血案:npm 全局包权限错乱彻底修复
前端·node.js·前端工程化
风骏时光牛马7 小时前
Raku正则匹配与数据批量处理实操案例
前端
nbwenren7 小时前
2026实测:Gemini 3 镜像站视觉能力实践——拍照原型图,一键生成 HTML+CSS 代码
前端·css·html
Lee川7 小时前
Prisma 实战指南:像搭积木一样设计古诗词数据库
前端·数据库·后端