Lit directive to make a subtree reactive, enabling the use of ReactiveControllers.
Install with NPM...
npm install @evanminto/lit-directive-stateful
... or Yarn.
yarn add @evanminto/lit-directive-stateful
Then import it into your JavaScript file:
import { stateful } from '@evanminto/lit-directive-stateful';
Normally in Lit, LitElement
s manage all reactive state via properties. This
directive enables you to create a stateful sub-section of your application, with
access to the same flexible ReactiveController
and ReactiveControllerHost
APIs available for full-fledged LitElement
components, without registering a
new element.
Let’s look at a code sample:
import { html } from 'lit';
import { stateful } from '@evanminto/lit-directive-stateful';
function MyComponent({ initialValue = 0 } = {}) {
return html`
${stateful(
(host) => new MyReactiveController(host),
(controller) => html`
<button type="button" @click=${() => controller.someMethod()}>Click me</button>
<output>${controller.someValue}</output>
`
)}
`;
}
The first argument is an init function that runs only the first time the
directive is connected to the DOM, and returns a state value that persists
between renders. It accepts a single argument: a ReactiveControllerHost
that
allows the init function to hook into the reactive lifecycle. Of course that
means you can return a ReactiveController
(or multiple) that hook into the
host.
The second argument is a render function that runs every render and accepts the state as an argument. It should return whatever you want to render (probably a Lit template or string).
Notably, the directive only attempts to re-render its own contents (the return value of the render function). If you want it to trigger re-renders further up the tree, you’ll need to manage that state elsewhere.
In my own application I found Lit’s assumption that reactivity lives at the
custom element level a bit limiting, but I really like the ReactiveController
pattern. I found it useful to attach controllers even to smaller functional
components or sub-templates.