最近,我发现自己实现了一个基于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 !"/>
)
}
如果我要遵循反应文档建议并将状态提升到父组件,我将拥有这个:
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}/>
)
}
现在,我不执行上述操作,因为我担心抽象泄漏,并且我的父组件必须同时处理创建时要操纵的状态和此弹出状态。
我的理由是,弹出窗口是导航流的中断,因此应在其自身的上下文中进行处理。
我是否使用这种(反)模式为自己的未来自我陷阱?
我批准第二个,更多的“ React-y”解决方案,因为:
最后,您可以通过一种方便使用的方式来调整弹出窗口:
const Component : React.FC = props => {
const [warningPopupShow, setWarningPopupShow] = useState(false);
return (
<button onClick={doDangerButton}>Dangerous button</button>
<WarningPopup warningText="Warning ! This is a dangerous button !"
show={warningPopupShow}
onShow={setWarningPopupShow} // Simply separate "shown" updates from
// acceptation action in the popup
onWarningAccept={doDangerAction}/>
)
}
简单,实用,惯用。