An Interest In:
Web News this Week
- March 19, 2024
- March 18, 2024
- March 17, 2024
- March 16, 2024
- March 15, 2024
- March 14, 2024
- March 13, 2024
Never ask for consent ever again
Dangerous operations often require a user input. For example, your UI might have a delete button that will destroy some resource, perform an irreversible operation or launch a missile.
In such cases, it is preferable to prompt the application user for consent before performing the dangerous operation.
This article implements a React abstraction that will prevent you from asking for consent ever again.
The valid approach that we want to stop using
In your view:
- Render a modal component that is controlled by a boolean state. This state controls whether the modal is opened or not.
- The modal component either calls a callback when the user clicks "Confirm" or implements the logic to perform the operation that requires confirmation.
In React pseudo-code:
const [opened, setOpened] = useState(false);const operation = useLaunchMissile();return ( <div> <button onClick={() => setOpened(true)}>Launch missile</button> <ConfirmationModal opened={opened} onConfirm={operation} onClose={() => setOpened(false)} /> </div>)
The problem with this approach is that you have to add code in your UI for each user confirmation.
A better approach
It is possible to create an abstraction around prompts, and to inject a method that calls this abstraction.
- First, we will create an abstraction around our prompts in React, we can create this with a context and a custom hook:
// `./context/DialogProvider`import {useState, createContext, useMemo} from 'react';export const DialogContext = createContext({});export function DialogProvider({ children }) { const [Dialog, setDialog] = useState(); // Dialog has type ReactNode const context = useMemo(() => ({ setDialog }), []); return ( <> <DialogContext.Provider value={context}>{children}</DialogContext.Provider> {Dialog} </> );}// `./hooks/use-dialog.js`import { useContext, useCallback, useEffect } from 'react';import { DialogContext } from '../context/DialogProvider';export function useDialog() { const { setDialog } = useContext(DialogContext); const close = useCallback(() => setDialog && setDialog(null), [setDialog]); const add = useCallback((node) => setDialog && setDialog(node), [setDialog]); useEffect(() => { return close; }, [close]); return { add, close, };}
The code above allows us to render a dialog/modal/prompt component from anywhere in the code.
- Second, we will use the abstraction above to render our prompt from a React hook:
// ./hooks/use-user-consent.jsximport { useDialog } from './use-dialog';import { ConfirmationDialog } from '../components/ConfirmationDialog';export function useUserConsent() { const { add, close } = useDialog(); return () => new Promise((resolve) => { const onClose = (accepted) => { close(); resolve(accepted); }; add( <ConfirmationDialog onAccept={() => onClose(true)} onDismiss={() => onClose(false)} />, ); });}
The code above returns a function that returns a Promise. This promise will resolve to true
if the user clicked confirm
, and resolve to false otherwise. If you wish to test the code, here is a dumb implementation of the ConfirmationDialog component:
// `./components/ConfirmationDialog.jsx`export function ConfirmationDialog({ onDismiss, onAccept }) { return ( <div> <div>Are you sure?</div> <button onClick={onAccept}>OK</button> <button onClick={onDismiss}>Close</button> </div> )}
- Ask for consent with our abstraction:
// App.jsimport { DialogProvider } from './context/DialogProvider'import { ConsentTest } from './components/ConsentTest'function App() { return ( <DialogProvider> <ConsentTest /> </DialogProvider> );}export default App;// `./components/components/ConsentTest.jsximport { useCallback } from "react";import { useUserConsent } from "../hooks/use-user-consent";export function ConsentTest() { const hasApproval = useUserConsent(); const callback = useCallback(async () => { const userConfirmed = await hasApproval(); alert(userConfirmed); }, [hasApproval]); return <button onClick={callback}>Test</button>}
Conclusion
We have just seen a way of abstracting asking for user consent.
This can easily be extended by adding properties to the "hasApproval
" method to have a configurable prompt message.
Original Link: https://dev.to/sbelzile/never-ask-for-consent-ever-again-1200
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To