Elliott Marquez challenged me to write a redux controller in the Lit community.
So let's get cracking!
Step 0: The Setup
First step let's make a new project and import some dependencies to help us develop.
mkdir controllers
cd controllers
git init
npm init --yes
npm i -D typescript lit
touch reducer.ts
Ok next we'll set up the controller class in reducer.ts
import type { ReactiveController, ReactiveControllerHost } from 'lit';
export class ReducerController implements ReactiveController {
constructor(
public host: ReactiveControllerHost,
) {
host.addController(this);
}
hostUpdate()?: void;
}
That hostUpdate
signature is just to keep typescript from complaining. 🤷.
Step 1: Reducers
Our controller essentially bolts some statefullness onto a function which takes
some state T
and some action A
and returns some other or the same state
T
. So let's formalize that:
type Reducer<T, A> = (state: T, action: A) => T;
The controller should take that reducer, along with some initial state, and pin them to the class instance.
export class ReducerController<T = unknown, A = unknown> implements ReactiveController {
public state: T;
constructor(
private host: ReactiveControllerHost,
public reducer: Reducer<T, A>,
public initialState: T,
) {
this.host.addController(this);
this.state = initialState;
}
hostUpdate?():void
}
Step 2: Actions
Believe it or not we're pretty much done. The last piece we need is to
implement a dispatch
method which takes an action A
and updates the host.
dispatch(action: A): void {
this.state = this.reducer(this.state, action);
this.host.requestUpdate();
}
And, as Chef John would say, that's it!
If we want to use our controller, we just create it on a compatible host (like LitElement) and we're off to the races: