Last active
January 29, 2020 12:28
-
-
Save teramotodaiki/f6f68a99543245c6e338474732d349bf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Button, Dialog, DialogActions, DialogTitle } from '@material-ui/core'; | |
import * as React from 'react'; | |
import { Subject } from 'rxjs'; | |
export interface IConfirm { | |
title: string; | |
ok: string; | |
cancel: string; | |
resolve: (ok: boolean) => void; | |
} | |
/** | |
* 現在表示している、あるいは保留されている内容 | |
*/ | |
const confirm$ = new Subject<IConfirm>(); | |
/** | |
* ユーザーに簡単な確認を求めるためのダイアログを表示する | |
* OK なら Promise<true>, そうでなければ Promise<false> を返す | |
*/ | |
export function useConfirm() { | |
return React.useCallback((title: string, ok: string, cancel: string) => { | |
return new Promise<boolean>(resolve => { | |
confirm$.next({ | |
title, | |
ok, | |
cancel, | |
resolve | |
}); | |
}); | |
}, []); | |
} | |
/** | |
* ユーザーに確認を求めるダイアログ | |
* このコンポーネントはアプリのなかで1つだけ存在する | |
*/ | |
export function ConfirmManager() { | |
// 現在表示すべき内容 | |
const [showing, setShowing] = React.useState<IConfirm>(); | |
const close = React.useCallback(() => setShowing(undefined), []); | |
// 新しい内容が追加されたら更新する | |
const stackRef = React.useRef<(IConfirm | undefined)[]>([]); | |
const update = React.useCallback(() => { | |
// スタックの最も上にある1件を表示する。なければダイアログを閉じる | |
setShowing(stackRef.current[0]); | |
}, []); | |
React.useEffect(() => { | |
return confirm$.subscribe( | |
value => { | |
stackRef.current.push(value); | |
update(); | |
}, | |
error => { | |
console.error(error); | |
close(); | |
}, | |
close | |
).unsubscribe; | |
}, []); | |
// 決定またはキャンセル | |
const ok = React.useCallback(() => { | |
stackRef.current[0]?.resolve(true); // Promise.resolve(true) | |
stackRef.current.shift(); // 今表示している内容を取り除く | |
update(); // 次があれば表示 | |
}, []); | |
const cancel = React.useCallback(() => { | |
stackRef.current[0]?.resolve(false); // Promise.resolve(false) | |
stackRef.current.shift(); // 今表示している内容を取り除く | |
update(); // 次があれば表示 | |
}, []); | |
return ( | |
<Dialog open={Boolean(showing)} onClose={close}> | |
<DialogTitle>{showing?.title}</DialogTitle> | |
<DialogActions> | |
<Button variant="contained" color="primary" onClick={ok}> | |
{showing?.ok} | |
</Button> | |
<Button variant="text" onClick={cancel}> | |
{showing?.cancel} | |
</Button> | |
</DialogActions> | |
</Dialog> | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Button } from '@material-ui/core'; | |
import * as React from 'react'; | |
import { useConfirm, ConfirmManager } from './ConfirmManager.tsx'; | |
export interface Example() { | |
const confirm = useConfirm(); | |
const dangerCallback = React.useCallback(async () => { | |
const yes = await confirm('本当にいいですか?', 'はい', 'いいえ'); | |
if (yes) { | |
// GO!!! | |
} | |
}, []) | |
return ( | |
<> | |
{/* これは React アプリケーション内に1つだけあれば良い */} | |
<ConfirmManager /> | |
{/* 確認を要する処理を実行するボタン */} | |
<Button onClick={dangerCallback}>実行</Button> | |
</> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment