Недавно я обнаружил, что реализую шаблон на основе ссылок, который, кажется, go против совета по документации реагирования .
Шаблон выглядит следующим образом:
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}/>
)
}
Теперь я не делаю вышеизложенного, потому что меня беспокоит утечка абстракции и мой родительский компонент должен обрабатывать как состояние, которым он был создан для манипуляции, так и это состояние всплывающего окна.
Мое мнение состоит в том, что всплывающее окно является прерыванием потока навигации и поэтому должно обрабатываться в своем собственном контексте.
Я ставлю ловушку для своего будущего я с этим (анти) паттерном?