Skip to content

Instantly share code, notes, and snippets.

@nicksheffield
Last active January 23, 2023 05:26
Show Gist options
  • Save nicksheffield/e0f795a2f4bfe30695e26061d3da7319 to your computer and use it in GitHub Desktop.
Save nicksheffield/e0f795a2f4bfe30695e26061d3da7319 to your computer and use it in GitHub Desktop.
react imperative modal paradigm
import * as React from 'react'
// the shape of a modal definition. A unique id and an element
interface ModalDefinition {
id: string
content: React.ReactNode
}
type AddModalFn = (def: ModalDefinition) => void
type RemoveModalFn = (id: string) => void
// this object is essentially used to globally access the "setModals" function from the ModalProvider.
// the big assumption we have to make here is that there is one ModalProvider and one react application in this codebase...
// this is probably fine.
const globalContainer: { addModal: AddModalFn; removeModal: RemoveModalFn } = {
addModal: () => {},
removeModal: () => {}
}
// this function is exported, and is used throughout our app to show modals
export const modal = (getContent: (close: () => void) => React.ReactNode) => {
const id = crypto.randomUUID()
const close = () => globalContainer.removeModal(id)
globalContainer.addModal({
id,
content: getContent(close)
})
}
export const ModalProvider = ({ children }) => {
// the list of modals is housed as react state in the provider
const [modals, setModals] = React.useState<ModalDefinition[]>([])
// upon mounting of the provider
React.useEffect(() => {
// we redefine the globalContainer methods to add and remove from the providers state
globalContainer.addModal = (def) => setModals(list => [...list, def])
globalContainer.removeModal = (id) => setModals(list => list.filter(x => x.id !== id))
}, [])
// below we render the app, and then our list of modals
return (
<>
{children}
<div id="modals">
{modals.map(modal => (
<div key={modal.id} className="modal">{modal.content}</div>
))}
</div>
</>
)
}
/// example usage:
const openMyModal = () => {
modal((close) => (
<div>
<div>My Modal</div>
<div>
<button onClick={() => close()}>Close</button>
</div>
</div>
))
}
<button onClick={() => openMyModal()}>Open Modal</button>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment