文章目录
- 子组件实现
- 父组件使用方式
-
- [情况 1:非受控使用(自己内部管理)](#情况 1:非受控使用(自己内部管理))
- [情况 2:受控使用(父组件控制)](#情况 2:受控使用(父组件控制))
- 这样设计的好处
场景:有一个react组件,他的功能是有一个title和Content,后者基于一个hidden的状态来控制。我现在希望这个组件内部支持toggle之外,父组件也可以去控制。怎么实现比较好?
这是一个非常经典的"受控 + 非受控组件"场景。
- 组件内部 有一个
hidden
状态,可以通过自身的 toggle 来控制显示/隐藏; - 父组件 也可以通过传入 props 来控制
hidden
状态; - 当父组件不传时,组件自行管理状态;当父组件传了时,组件跟随父组件状态变化。
推荐的实现方式是使用 "受控优先 + 非受控兜底" 模式。
子组件实现
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
就非常关键------它让子组件的行为能回传给父组件来同步状态。