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

rx-ducks-middleware

v0.1.0

Published

creates RxJS based middleware for Redux

Downloads

9

Readme

rx-ducks-middleware (alpha)

** WARNING: This module is purely experimental **

Creates RxJS 5-based middleware for Redux.

  • Dispatch a function that returns an observable of actions, a promise of action or iterable of actions.
  • Function is provided a stream of all actions, useful for composition with the current dispatched observable (think things like takeUntil or zip)
  • Function is also provided a reference to the store which can be used to get the state or even dispatch.

Install

NOTE: This has a peer dependencies of [email protected].* and redux, which will have to be installed as well.

npm i -S rx-ducks-middleware

Usage

Basic

With rxDucksMiddleware, you can dispatch any function that returns an observable, a promise, an observable-like object or an iterable. The basic call looks like:

// using RxJS
dispatch(() => Rx.Observable.of({ type: 'ASYNC_ACTION_FROM_RX' }).delay(1000));
// using a Promise
dispatch(() => Promise.resolve({ type: 'ASYNC_ACTION_FROM_PROMISE'}));
// using an Array of actions
dispatch(() => [{ type: 'ACTION_1' }, { type: 'ACTION_2' }]);
// using a generator of actions
dispatch(() => (function* () {
  for (let i = 0; i < 10; i++) {
    yield { type: 'SOME_GENERATED_ACTION', value: i };
  }
}()))

Cancellation

It's recommended to dispatch an action to cancel your async action with Rx. This can be done by leveraging the first argument to your dispatched function, which returns all actions. With that you can use takeUntil to abort the async action cleanly and via composition.

dispatch((actions) => Observable.timer(1000)
  .map(() => ({ type: 'TIMER_COMPLETE'}))
  .takeUntil(actions.filter(a => a.type === 'ABORT_TIMER')))

// elsewhere in your code you can abort with a simple dispatch
dispatch({ type: 'ABORT_TIMER' });

You can also cancel an async dispatch by using the return value from your dispatch, which is an Rx Subscription. This works well for other types that don't have cancellation, like promises, but internally will really use "disinterest" to stop the resolved value from propagating.

let subscription = dispatch(() => Promise.resolve({ type: 'DELAYED_ACTION' }));

// will stop DELAYED_ACTION from firing
subscription.unsubscribe();

Other API Notes

The second argument to your dispatched function will be the store instance itself. This gives you the ability to getState() on your store in case you need to assert some condition before dispatching your next async message. It also gives you the ability to dispatch() explicitly.

Basic Dispatch Type Signature

If it helps to think about it this way, in a TypeScript-style type definition, the dispatch function would look like this when used to dispatch an action asynchronously:

dispatch = ((actions?: Observable<Action>, store?: ReduxStore) => Observable<Action>) => Subscription;

Example

Below is a basic example of it how it might work in React.

import { Component } from 'react';
import { connect } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { rxDucksMiddleware } from 'rx-ducks-middleware';
import * as Rx from 'rxjs';

// Just the plain redux reducer.
const reducer = (state = {}, action) => {
  switch (action.type) {
    case 'DATA_LOADING':
      return { ...state, loading: true };
    case 'DATA_LOADED':
      return { ...state, loading: false, data: action.data };
    case 'ABORT_LOAD':
      return { ...state, loading: false };
  }
  return state;
};

// making a store
const store = createStore(reducer, applyMiddleware(rxDucksMiddleware()));

// HERE BE THE DUCKS
const loadData = () => (actions, store) => Observable.of('hello world')
                .delay(1000)
                .map(data => ({ type: 'DATA_LOADED', data })
                .startWith({ type: 'DATA_LOADING' })
                .takeUntil(actions.filter(a => a.type === 'ABORT_LOAD'));

// plain old action
const abortLoad = () => ({ type: 'ABORT_LOAD' });

const mapStateToProps = ({ data, loading }) => ({ data, loading });

const mapDispatchToProps = (dispatch) => ({
  loadData: () => dispatch(loadData()),
  abortLoad: () => dispatch(abortLoad())
});

const MyComponent = ({ loading, data, loadData, abortLoad }) => (
  <div>
    <button onClick={loadData}>load data</button>
    <button onClick={abortLoad}>abort load</button>
    <div>Loading: {loading}</div>
    <pre>{JSON.stringify(data, null, 2)}</pre>
  </div>
);

export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);

:shipit: