@gapstack/react-imperative-render
v0.0.7
Published
A headless and unopinionated solution to rendering elements from within callbacks and effects. Inspired by [Ant Design's Notifications](https://ant.design/components/notification/) and [Notistack](https://github.com/iamhosseindhv/notistack) but designed t
Downloads
6
Readme
React Imperative Render
A headless and unopinionated solution to rendering elements from within callbacks and effects. Inspired by Ant Design's Notifications and Notistack but designed to be UI framework agnostic and useful for much more than toast style notifications.
Should you use this?
Rendering elements imperatively can be an anti-pattern. There are good reasons that react pushes us towards declarative rendering, so this is not an excuse to stop doing that.
This said, doing things declaratively can also be considered an anti-pattern at times, for instance when building modals the need to manage aspects like an isOpen
state to move a user through a flow can add a lot of complexity and indirection, where it might be cleanest to handle this within the callback which triggers it.
As a rule of thumb, if you want to serve ephemeral information or UI in response to a user interaction, or do more after some period of time or future interaction, imperative-render might be a clean solution.
Installation
# NPM
npm install @gapstack/react-imperative-render
# Yarn
yarn add @gapstack/react-imperative-render
Basic Usage
import { createInstance, ImperativeRendererProvider } from '@gapstack/react-imperative-render'
import { useRef } from 'react'
// A Renderer requires an model used to render elements
type Model = {
count: number
}
// Create an instance
const ImperativeRenderer = createInstance<Model>({
container: <ul />,
renderElement: (model, params) => {
return <li>Element {model.count}</li>
},
})
// Render the Provider and the Root element
export default function BasicExample() {
return (
<ImperativeRendererProvider>
<Component />
<ImperativeRenderer.Root />
</ImperativeRendererProvider>
)
}
export function Component() {
const counter = useRef(0)
// There are multiple hooks for difference use cases
const render = ImperativeRenderer.useRender()
return (
<button
onClick={() => {
const count = counter.current++
// The render hook just returns a destroy function
const destroy = render({
count,
})
}}
>
Add Element
</button>
)
}
Multiple Renderers
import { createInstance, ImperativeRendererProvider } from '@gapstack/react-imperative-render'
// By creating multiple renderers you can have different behaviours and styles for different use cases
const AlertsRenderer = createInstance(/**/)
const ModalRenderer = createInstance(/**/)
function Main() {
return (
<ImperativeRendererProvider>
<MyComponent />
<AlertsRenderer.Root />
<ModalRenderer.Root />
</ImperativeRendererProvider>
)
}
Developing
To run the docs for development: yarn docs
To deploy: yarn build && cd dist/packages/imperative-render && npm publish --access=public