【发布时间】:2020-02-12 13:44:32
【问题描述】:
最近我发现自己实现了一个基于 ref 的模式,这似乎与 react documentation advice 背道而驰。
模式是这样的:
type Callback = () => void;
type CallbackWrapper = {callback : Callback}
interface IWarningPopupRef{
warn : (callback : Callback) => void;
}
interface IWarningPopupProps{
warningText : string;
}
const WarningPopup = forwardRef<IWarningPopupRef, IWarningPopupProps>(
const [show, setShow] = useState(false);
const [callback, setCallback] = useState<CallbackWrapper | null>(null);
const warn = (callback : Callback) => {
setShow(true);
setCallback({callback});
}
const acceptWarning = () => {
setShow(false);
setCallback(null);
if(callback != null) callback.callback();
}
useImperativeHandle(ref, () => ({
warn
}));
(props, ref) => {
return (
<div style={{
visibility:(show)?"visible":"hidden"
}}>
{props.warningText}
<button onClick={acceptWarning}>Accept</button>
</div>
)
}
)
const Component : React.FC = props => {
const warningPopupRef = useRef<IWarningPopupRef>(null);
const doDangerButton = () => {
warningPopupRef.current!.warn(() => {
doDangerAction();
});
}
return (
<button onClick={doDangerButton}>Dangerous button</button>
<WarningPopup ref={warningPopupRef}
warningText="Warning ! This is a dangerous button !"/>
)
}
如果我要遵循 react 文档的建议并将状态提升到父组件,我会有这个:
interface IWarningPopupProps{
warningText : string;
show : boolean;
onWarningAccept : () => void;
}
const WarningPopup : React.FC<IWarningPopupProps> = props => {
return (
<div style={{
visibility:(props.show)?"visible":"hidden"
}}>
{props.warningText}
<button onClick={props.onWarningAccept}>Accept</button>
</div>
)
}
const Component : React.FC = props => {
const [warningPopupShow, setWarningPopupShow] = useState(false);
const doDangerButton = () => {
setWarningPopupShow(true);
}
const acceptWarning = () => {
setWarningPopupShow(false);
doDangerAction();
}
return (
<button onClick={doDangerButton}>Dangerous button</button>
<WarningPopup warningText="Warning ! This is a dangerous button !"
show={warningPopupShow}
onWarningAccept={acceptWarning}/>
)
}
现在我不执行上述操作,因为我担心抽象泄漏以及我的父组件必须同时处理它被创建来操作的状态和这个弹出状态。
我的理由是弹出窗口是导航流程的中断,因此应该在它自己的上下文中处理。
我是否用这种(反)模式为未来的自己设下陷阱?
【问题讨论】:
标签: reactjs typescript design-patterns anti-patterns