State management using Redux libraries.
This library forwards exports from Redux Toolkit and ReduxSaga.
Note
I use both of these libraries heavily in several of my projects and it makes it easier to update a single dependency, rather than keep two up-to-date.
This library also provides the following additional APIs:
createAsyncAction
: Custom async action creator based on thecreateAsyncAction
export fromtypesafe-actions
ActionType
: Utility type that allows you to get the actiontype
andpayload
types from the actionforwardChannelAction
: Simple utility function for dispatching actions emitted from anEventChannel
Consult the Redux Toolkit and Redux Saga documentation for usage of forwarded exports.
Important
The exports from redux-saga/effects
are forwarded directly, as well as via an effects
object.
If your build tool supports tree-shaking, any unused exports will be excluded from the resulting build.
The example below exhibits how to use the additional exports.
import {
createAsyncAction,
all, // Import individual effects
effects as E, // Or all of them
eventChannel,
forwardChannelAction,
type ActionType,
type EventChannel,
type SagaIterator,
} from "@laserware/stasis";
type Request = { value: string };
export const doSomething = createAsyncAction<
Request, // Payload for the `.request` action.
string, // Payload for the `.success` action.
string // Payload for the `.failure` action.
>("@app/doSomething");
export function* someSaga(): SagaIterator {
yield all([
E.takeEvery(doSomething.request, handleRequestSaga),
E.takeEvery(doSomething.success, handleSuccessSaga),
E.takeEvery(doSomething.failure, handleFailureSaga),
]);
}
function* handleRequestSaga(
action: ActionType<typeof doSomething.request>,
): SagaIterator {
// TypeScript knows this is a `Request` because of the `ActionType`
// annotation above:
const value = action.payload.value;
const resizeChannel = yield E.call(createResizeChannel);
// This will dispatch the action whenever the window is resized:
yield E.takeEvery(resizeChannel, forwardChannelAction);
// ...
}
function* handleSuccessSaga(
action: ActionType<typeof doSomething.success>,
): SagaIterator {
// TypeScript knows this is a string because of the `ActionType`
// annotation above:
const value = action.payload;
// ...
}
function* handleFailureSaga(
action: ActionType<typeof doSomething.failure>,
): SagaIterator {
// TypeScript knows this is a string because of the `ActionType`
// annotation above:
const value = action.payload;
// ...
}
function createResizeChannel(): EventChannel<
ActionType<typeof doSomething.success>
> {
return eventChannel((emit) => {
const handleWindowResize = () => {
emit(doSomething.success());
};
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
});
}
You'll need to install Bun prior to doing any development. Once installed, run bun install
to install dependencies.