Render Hook Pattern in React
Tags: react, javascript, reactnative
Published: 2020-04-17 16:12:02


Working on a React code base I found my self in a need to display many confirmation modals.
I got frustrated after the third one and found a nifty pattern to use: **returning the modal component itself from a hook.**

I assume that a this point in time there is no longer a need to introduce the concept of hooks in React. However if you need a refresher you might want to check https://reactjs.org/docs/hooks-intro.html
So my basic Idea was to use an API that will look roughly like that:

```javascript
const ComponentWithDangerAction = () => {
  const [Modal, onClick] = useConfirm({
    onConfirm: ({ id }) => alert("deleted item id: " + id),
    onDismiss: alert,
    title: "Danger Zone",
    message: "This action is irreversible. Are you sure you want to continue?"
  });
  return (
    <div className="App">
      <Modal />
      <Button onClick={() => onClick({ id: 5 })}>
        Press here to delete something important
      </Button>
    </div>
  );
};
```

Next step is to create the useConfirm hook itself and it easiest of course to start with a minimal non crashing api (assuming we have a Modal component).

```javascript
const useConfirm = () => {
  const onClick = () => null;
  const ConfirmModal = () => <Modal />
  return [ConfirmModal, onClick];
}
```

Now adding disclosure related state and callbacks functionality

```javascript
const useConfirm = ({onConfirm, onDismiss, message }) => {
  const [isOpen, setOpen] = useState(false);
  const toggle = setOpen(!isOpen);
  const onClick = () => toggle();
  const handleConfirm = () => {
    onConfirm && onConfirm();
    toggle();
  }
  const handleDismiss = () => {
    onDismiss && onDismiss();
    toggle();
  }
  const ConfirmModal = () => (
    <Modal isOpen={isOpen} onClose={toggle}>
      <span>{message}</span>
      <button onClick={handleConfirm}>Confirm</button>
      <button onClick={handleDismiss}></Dismiss>
    </Modal>)

  return [ConfirmModal, onClick];
}
```

Almost Done! The only problem is I want to be able to pass arguments to the confirm function (I want to delete a specific item from a list).
My solution was to store arguments passed to onClick to the state of the hook. That way when Confirm button is pressed I can call the onConfirm callback with the arguments passed to it.

```javascript
const useConfirm = ({onConfirm, onDismiss, message }) => {
  const [isOpen, setOpen] = useState(false);
  const [confirmArgs, setConfirmArgs] = useState(false);
  const toggle = setOpen(!isOpen);
  const onClick = (args) => {
    setConfirmArgs(args); // storing the args
  };
  const handleConfirm = () => {
    onConfirm && onConfirm(confirmArgs); // using the args
    toggle();
  }
  const handleDismiss = () => {
    onDismiss && onDismiss();
    toggle();
  }
const ConfirmModal = () => (
    <Modal isOpen={isOpen} onClose={toggle}>
      <span>{message}</span>
      <button onClick={handleConfirm}>Confirm</button>
      <button onClick={handleDismiss}></Dismiss>
    </Modal>)
return [ConfirmModal, onClick];
}
```

Hope you will find this pattern useful :)

you can find a more complete example on [codesandbox](https://codesandbox.io/s/useconfirm-n3v5y)

And of course follow me on twitter [@SlutskyTom](https://twitter.com/slutskytom)