Security News
Weekly Downloads Now Available in npm Package Search Results
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.
Simple state update pattern for modern React apps. Allows for updating both immutable state as used by React-Redux and mutable state for computationally intensive desktop applications. No generators.
Simple state update pattern for modern React apps. Allows for updating both immutable state as used by React-Redux and mutable state for computationally intensive desktop applications. No generators.
$ yarn add tinysaga
Comes with TypeScript typings out of the box, as well as ESM support and tree shaking.
Redux-Saga is a great library which allows applications to manage the complex state updates and side effects that happen in many React-Redux applications. It is a crucial part of the current frontend software stack.
However, the library itself is quite complex, which can cause problems in the following ways:
yield
and yield*
, or why you would want to yield take
inside of a while (true)
loop.Tinysaga supports most of the common put()
, takeEvery()
, and take()
workflows from Redux-Saga, leaving only the most complex uses (like debouncing, throttling, and cancellation) to other sophisticated libraries using plain old JavaScript.
At its core, Tinysaga is really just an event bus that integrates into React-Redux.
Emitter
.Emitter
is wired up with handlers for each Action type
in your application. Those handlers are free to do whatever they want, such as reducing a Store's state, changing any mutable state you have, or dispatching other actions.There are a set of helpful Effects that Tinysaga exports, such as take()
and once()
which allow you to compose the low-level Emitter primitive into more powerful constructs. No generators involved.
// Utility function for defining typesafe actions.
function defineAction<T = undefined>(type: string): IActionDefinition<T>;
// The core Emitter type to use with Tinysaga for handling actions.
class Emitter {
put(action: IAction): void;
on<T>(type: IActionType<T>, handler: (payload: T) => void): () => void;
}
// A Store class to use with Tinysaga. No redux or reducers required --
// just set the Store's state directly from your Tinysaga handlers.
class Store<S> implements IStore<S> {
constructor(state: S, dispatch: (action: IAction) => void);
readonly state: S;
setState(nextState: S): void;
getState(): S;
dispatch(action: IAction): void
subscribe(cb: () => void): () => void;
flush(): void;
}
// Effects to use for convenience in Tinysaga handlers.
function on<T>(emitter: IEmitter, type: IActionType<T>, cb: (t: T) => void): () => void;
function once<T>(emitter: IEmitter, type: IActionType<T>, cb: (t: T) => void): () => void;
function take<T>(emitter: IEmitter, type: IActionType<T>): Promise<T>
function take<T>(emitter: IEmitter, type: IActionType<T>, maxWait: number): Promise<T | null>;
function put(emitter: IEmitter, action: IAction): void;
const FetchUser = defineAction<{ userId: string }>("FetchUser");
const FetchUserSuccess = defineAction<{ data: IUserData }>("FetchUserSuccess");
const FetchUserFailed = defineAction<{ message: string }>("FetchUserFailed");
on(emitter, FetchUser.TYPE, async ({ userId }) => {
// Note: `userId` and all of these calls are type-aware! No saga ReturnType shenanigans
try {
const data = await Api.fetchUser(userId);
put(emitter, FetchUserSuccess({ data }));
} catch (e) {
put(emitter, FetchUserFailed({ message: e.message }));
}
});
This snippet shows how multiple action types can be combined to implement complex behavior. Here we use lodash.debounce()
for most of the heavy lifting.
const DismissPopover = defineAction("DismissPopover");
const PopoverAnchorEnter = defineAction("PopoverAnchorEnter");
const PopoverEnter = defineAction("PopoverEnter");
function popoverHandler(emitter: IEmitter) {
const debouncedHide = lodash.debounce(() => {
store.setState({ ...store.state, popover: undefined });
}, 500);
on(emitter, DismissPopover.TYPE, () => {
debouncedHide();
});
on(emitter, PopoverAnchorEnter.TYPE, () => {
debouncedHide.cancel();
});
on(emitter, PopoverEnter.TYPE, () => {
debouncedHide.cancel();
});
}
For comparison, equivalent Redux-Saga code is something like:
const DismissPopover = defineAction("DismissPopover");
const PopoverAnchorEnter = defineAction("PopoverAnchorEnter");
const PopoverEnter = defineAction("PopoverEnter");
function* popoverSaga() {
yield fork(function* () {
while (true) {
yield takeLatest(DismissPopover.TYPE, function* () {
const { pass } = yield race({
anchorEnter: take(PopoverAnchorEnter.TYPE),
enter: take(PopoverEnter.TYPE),
pass: delay(500),
});
if (pass) {
yield put(DismissPopoverInternal()); // goes off to a reducer somewhere
}
};
}
});
}
Contributions are definitely welcome!
This is still an early-stage project, so the most likely next major investment will be a documentation site.
FAQs
Simple state and logic management library for modern React apps.
The npm package tinysaga receives a total of 2 weekly downloads. As such, tinysaga popularity was classified as not popular.
We found that tinysaga demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.
Security News
A Stanford study reveals 9.5% of engineers contribute almost nothing, costing tech $90B annually, with remote work fueling the rise of "ghost engineers."
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.