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

相关推荐
diudiu_333 分钟前
XSS跨站脚本攻击
前端·xss
终极前端开发协会3 分钟前
【web前端 - 齐枭飞】乾坤【qiankun】应用,主项目与子项目交互详细代码,里面有详细代码,可直接粘贴过去 直接应用 ,
前端·前端框架·交互
闲蛋小超人笑嘻嘻19 分钟前
localStorage用法详解
前端
Swift社区22 分钟前
用 RN 的渲染模型,反推 Vue 列表的正确拆分方式
前端·javascript·vue.js
Mr_chiu22 分钟前
微前端从入门到精通:Vue开发者的大型应用架构演进指南
前端·架构
光影少年25 分钟前
前端开发桌面应用开发,Flutter 与 Electron如何选?
javascript·flutter·electron
Violet_YSWY26 分钟前
Vue-Pinia defineStore 语法结构
前端·javascript·vue.js
全栈陈序员26 分钟前
v-if 和 v-for 的优先级是什么?
前端·javascript·vue.js·学习·前端框架·ecmascript
xinyu_Jina28 分钟前
Info Flow:大规模列表渲染中的UI虚拟化、数据懒-加载与前端性能工程
前端·ui
GISer_Jing31 分钟前
JD AI全景:未来三年带动形成万亿规模的人工智能生态
前端·人工智能·aigc