npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

redux-saga-factory

v1.1.0

Published

> Next generation sagas using classes and decorators

Downloads

3

Readme

redux-saga-factory 🏭

Next generation sagas using classes and decorators

codecov CircleCI semantic-release

Introduction

Sagas are great, but they don’t always fit nicely inside large scale projects since:

  1. They are nothing more than generator functions, so it is impossible to use them with dependency injection patterns.
  2. You often have to type repeated boilerplate only to wrap the actual action handler.

This library will allow you to:

  1. Create sagas using factory classes.
  2. Leverage decorators to yield common saga patterns (hence removing boilerplate).

Installation

yarn install redux-saga-factory reflect-metadata

Usage

1. Create Saga using class & decorators

import 'reflect-metadata'
import { take, SagaFactory } from 'redux-saga-factory'

export class KickassSaga extends SagaFactory {

    @take("some-action")
    *onSomeAction(action) {
        const result = yield call(fetchSomething);
        return result.data;
    }
}

2. Use the saga

import { KickassSaga } from "./KickassSaga.ts";

// Setup the factory 
const kickassSaga = new KickassSaga(/* dependencies? */);

// Get the sagas
const sagas = kickassSaga.getSagas();

// sagas === { onSomeAction: [Function: onSomeAction]}

// Create the store as usual
import { Action, createStore, applyMiddleware } from "redux";
import sagaMiddlewareFactory from "redux-saga";

const sagaMiddleware = sagaMiddlewareFactory();
const store = createStore(reducer, applyMiddleware(sagaMiddleware));

Object.values(saga).forEach(item => sagaMiddleware.run(item));

⚠️ You must import "reflect-metadata" polyfill and you should only import it once in the code.

Deeper look

Say you have this saga:

function* someSaga() {
  while (true) {
    const action = yield take("some_action");
    yield call(sagaWorker, action);
  }
}

function* sagaWorker(action) {
  // do the magic
}

We can change it to this

class SomeSaga {
  @take("some_action")
  static *sagaWorker(payload) {
    // do the magic
  }
}

// and use it by...

const sagas = SagaFactory.fromMetadata(SomeSaga);

// sagas = { some_action_saga: [Function: sagaWorker] }

Or, if we want to add dependency injection:

class SomeSaga extends SagaFactory {

	private readonly logger :ILogger;

	constructor(logger:ILogger){
		this.logger = logger;
	}

	@take("some_action")
	*sagaWorker(payload) {
		this.logger.debug("saga with di!")
		// do the magic
	}

}

// and use it by...

const factory = new SomeSaga(loggerInsatance);

const sagas = factory.getSagas()

// sagas = { some_action_saga: [Function: sagaWorker] }

You can also use the Factory to generate multiple sagas or use different effect patterns:

class MultiSaga extends SagaFactory {

	@take("some_action")
	*sagaWorker(payload) {
		logger.debug("saga with di!")
		// do the magic
	}

	@takeLatest("some_action")
	*anotherSagaWorker(payload) {
		// using takeLatest effect instead of take
	}
}

Use with typescript-fsa:

This library is 100% compatible with typescript-fsa, which provides "type-safe experience with Flux actions with minimum boilerplate".

import { actionCreatorFactory } from 'typescript-fsa'

const actionCreator = actionCreatorFactory();
const fsaAction = actionCreator<{ foo: string }>("SUBMIT_ACTION");

class FsaSaga extends SagaFactory {

	@take(fsaAction)
	*sagaWorker(payload) {
		// do the magic
	}

}

Use with typescript-fsa-redux-saga

Another great library is typescript-fsa-redux-saga which easily wraps sagas with async actions. Resulting saga dispatches started action once started and done/failed upon finish.

This can be achieved automatically with redux-saga-factory by passing the AsyncAction creator as an argument:

import { actionCreatorFactory } from 'typescript-fsa'

const actionCreator = actionCreatorFactory();
const fsaAction = actionCreator<{ foo: string }>("SUBMIT_ACTION");
const fsaAsyncAction = actionCreator.async<{ foo: string }, { bar: string}>("SUBMIT_ASYNC_ACTION");

class FsaSaga extends SagaFactory {

	@take(fsaAction, fsaAsyncAction)
	*sagaWorker(payload) {
		// do the magic
	}

}

// store.dispatch(fsaAction({foo: 'bar'}))
//
// Actions fired:
//
// 1. SUBMIT_ACTION
// 2. SUBMIT_ASYNC_ACTION_STARTED
// --- Here sagaWorker will be called ---
// 3. SUBMIT_ASYNC_ACTION_DONE

Use without class

TBA

Use with custom saga pattern

TBA