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

相关推荐
1024肥宅1 小时前
JavaScript 拷贝全解析:从浅拷贝到深拷贝的完整指南
前端·javascript·ecmascript 6
欧阳天风1 小时前
js实现鼠标横向滚动
开发语言·前端·javascript
局i2 小时前
Vue 指令详解:v-for、v-if、v-show 与 {{}} 的妙用
前端·javascript·vue.js
码界奇点2 小时前
Java Web学习 第15篇jQuery从入门到精通的万字深度解析
java·前端·学习·jquery
小鑫同学2 小时前
Alias Assistant:新一代 macOS Shell 别名管理解决方案
前端·前端工程化
꒰ঌ小武໒꒱2 小时前
RuoYi-Vue 前端环境搭建与部署完整教程
前端·javascript·vue.js·nginx
名字越长技术越强3 小时前
前端之相对路径
前端
望道同学3 小时前
PMP/信息系统项目管理师 9 张 思维导图【考试必备】
前端·后端·程序员
局i4 小时前
Vue 中 v-text 与 v-html 的区别:文本渲染与 HTML 解析的抉择
前端·javascript·vue.js
fruge4 小时前
接口 Mock 工具对比:Mock.js、Easy Mock、Apifox 的使用场景与配置
开发语言·javascript·ecmascript