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-polling

v1.1.5

Published

Convenient way to support polling in your Redux app so you can focus on the business logic

Downloads

59

Readme

Redux Polling

Convenient way to support polling in your Redux app so you can focus on the business logic

NPM Version

Almost every app contains charts, progress bars or components that consist on repeated data sampling. This is done by Polling. Support polling in React-Redux application can be frustrating. Each polling scenario requires to write a dedicated reducer and actions, implement the polling (all the setTimeout / setInterval stuff), deal with history and this is even before writing the business logic of polling itself. Redux Polling provides a convenient way to support polling in React-Redux application so you will be able to focus on the business logic right away instead of dealing with all the boilerplate code. The setup is done by adding a middleware and you are ready to go.

You can see a demo here or read the demo source code here.

Installation

npm install --save redux-polling

Or

yarn add redux-polling

Setup

  1. Add reduxPollingMiddleware middleware to your Redux store:
import { createStore, applyMiddleware, compose } from 'redux';
import { reduxPollingMiddleware } from 'redux-polling';
import rootReducer from './path/to/your/root/reducer';

const initialState = {};
const middleware = [
    reduxPollingMiddleware,
];

const composedEnhancers = compose(
    applyMiddleware(...middleware),
);

const store = createStore(
    rootReducer,
    initialState,
    composedEnhancers,
);

export default store;
  1. Add reduxPollingReducer reducer to your root reducer:
import { combineReducers } from 'redux';
import { reduxPollingNamespace, reduxPollingReducer } from 'redux-polling';

export default combineReducers({
    .....
    .....
    [reduxPollingNamespace]: reduxPollingReducer,
});
  1. Your application is ready to use Redux Polling everywhere.

Usage example

Let's say we want to implement a chart page that consist on data polling. The page has two components:

  1. Action panel component that contains two buttons: "Start Polling", "Stop Polling" and "Reset Polling".
  2. Chart component that shows the data.

Redux Polling provides everything for those components: start and stop actions for the buttons and selectors for receiving the results and history. All we left to do is to implement the polling logic that fetches the data once (Redux Polling will call it on each interval):

import { createPollingActions, getPollingState } from 'redux-polling';
import { createSelector } from 'reselect';
import fetchNextPoint from './path/to/your/points/service';

/* Actions */
const pollingInterval = 1000;
const historyLength = 30;

async function polling() {
    const point = await fetchNextPoint();
    return point;
}

export const actions = createPollingActions('pointPolling', polling, pollingInterval, historyLength);

/* Selectors */
const isPollingActive = state => getPollingState(state, 'pointPolling').isActive;
const getPointHistory = state => getPollingState(state, 'pointPolling').history;
const getLastPoint = state => getPollingState(state, 'pointPolling').lastEntry;

export const selectors = {
    isPollingActive, getPointHistory, getLastPoint,
};

This module exports two items: actions and selectors.
actions is an object that contains three action creators: start(), stop() and reset().
selectors is an object with selectors that our app needs.
Please notice the use of createPollingActions() and getPollingState().

That's all for the polling implementation. Now we can create the components.

  1. Actions Panel:
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { actions as pointPollingActions } from './state/point-polling';

function ActionsPanel(props) {
    const { startPolling, stopPolling } = props;
    return (
        <div>
            <button type="button" onClick={ () => startPolling() }>
                Start Polling
            </button>
            <button type="button" onClick={ () => stopPolling() }>
                Stop Polling
            </button>
            <button type="button" onClick={ () => resetPolling() }>
                Reset Polling
            </button>
        </div>
    );
}

ActionsPanel.propTypes = {
    startPolling: PropTypes.func,
    stopPolling: PropTypes.func,
    resetPolling: PropTypes.func,
};

ActionsPanel.defaultProps = {
    startPolling: () => {},
    stopPolling: () => {},
    resetPolling: () => {},
};

const mapDispatchToProps = dispatch => ({
    startPolling: () => dispatch(pointPollingActions.start()),
    stopPolling: () => dispatch(pointPollingActions.stop()),
    resetPolling: () => dispatch(pointPollingActions.reset()),
});

export default connect(
    undefined,
    mapDispatchToProps,
)(ActionsPanel);
  1. Chart (I will not get into implementation details of the chart since this is not the topic here):
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import LineChart from 'my-favorite-charts-library';
import { selectors as pointPollingSelectors } from './state/point-polling';

function Chart(props) {
    const { isPollingActive, lastPoint, history } = props;
    return (
        <div>
            <div>
                { isPollingActive ? 'Polling Active' : 'Polling Inactive' }
            </div>
            <div>
                { `Last fetched point is ${lastPoint}` }
            </div>

            <LineChart data={ history } />
        </div>
    );
}

Chart.propTypes = {
    isPollingActive: PropTypes.bool,
    lastPoint: PropTypes.number,
    history: PropTypes.arrayOf(PropTypes.number),
};

Chart.defaultProps = {
    isPollingActive: false,
    lastPoint: undefined,
    history: [],
};

const mapStateToProps = state => ({
    isPollingActive: pointPollingSelectors.isPollingActive(state),
    lastPoint: pointPollingSelectors.getLastPoint(state),
    history: pointPollingSelectors.getPointHistory(state),
});

export default connect(
    mapStateToProps,
)(Chart);

Cool.

Documentation

redux-polling module exports several modules:

  • reduxPollingMiddleware, reduxPollingReducer and reduxPollingNamespace which are required for setup.
  • createPollingActions and getPollingState which are required for polling creation and usage.

reduxPollingMiddleware

reduxPollingMiddleware is the middleware that should be added to the store. You can see an example here. This middleware is used for intercepting polling actions and operate the polling logic.

reduxPollingReducer

reduxPollingReducer is the reducer that should be added to the root reducer and reduxPollingNamespace is the name for that reducer. You can see an example here. This reducer operate the polling state.

createPollingActions(pollingName, callbacks, pollingInterval, historyLimit)

createPollingActions() is the method that creates for you the polling redux actions. It expects the following arguments:

  • pollingName String, required Is a name for this polling operation. You may name your polling operation in any name you like.
  • callbacks Object or Function, required Is an object that contains callbacks for managing the polling cycle. The most important and the only required callback is the polling function which should do the polling logic. You can find all the available callbacks here. Passing a function func instead of an object is equal to passing a callbacks object that contains only the polling function: { polling: func }.
  • pollingInterval Number, optional, default is 5000ms Is the polling interval in milliseconds. Each interval starts when polling cycle ends and trigger a new polling cycle.
  • historyLimit Number, optional, default is 1 Is the number of entries you wish to store for this polling operation. Use 0 (zero) to not store any history, and -1 for unlimited history.

createPollingActions() returns an object with three action creators: start(), stop() and reset(). Dispatching them will start, stop and reset the polling operation.
Important: Any argument that will be supplied to start() will be passed to the polling callback:

async function polling(accountId) {
    const point = await fetchNextPoint(accountId);
    return point;
}

const actions = createPollingActions('pointPolling', { polling }, 1000, 30);

...
...
const accountId = 428;
dispatch(actions.start(accountId));
...
...
dispatch(actions.stop());
...
...
// When required to reset the polling state
dispatch(actions.reset());

In this example polling started with account id as an argument (actions.start(accountId);). When the polling(accountId) method will be called, the accountId argument that was provided to start() will also be provided to polling(). There is no limitation on the arguments start() can get. They simply will be passed to polling().

getPollingState(state, pollingName)

getPollingState(pollingName) is a helper selector to retrieve the state of the polling operation named by pollingName argument. Like any other selector it gets the global state (state) and the name of the required polling operation state (pollingName). The returned polling state is an object that looks like:

{
    isActive: false,            // Indicates whther the polling is activated or not
    history: [],                // History entries
    lastEntry: undefined,       // The last fetched entry
}

Available Callbacks

The second argument createPollingActions() expected is an object with callbacks. Those callbacks are called during a polling cycle. The available callbacks are:

  • polling(...args, getState) required Each interval starts with calling to the polling callback that should do a single fetch / calculation and return a single entry. ...args are the arguments that was provided to the start(args) action. getState() method is also provided as the last argument so you can query your state. This method can be asynchronous and can return a promise. The returned / resolved value is store as an entry in the polling history.
    Sometimes you may want to return and store multiple items in the history for single polling. You can do that by returning the following { multipleEntries: true, entries: [ ...entries ] }.
    Example:
async function polling(accountId, getState) { // accountId was provided by start() action
    const state = getState();
    const pointsCount = selectors.getPointsCount();
    const points = await fetchMultiplePoints(accountId, pointsCount);
    // points is an array
    return { multipleEntries: true, entries: points};
}
  • shouldAddEntry(entry, getState) optional This callback is called right before adding an entry to the state. It gets a single entry (which is the response of the polling callback) and getState() method. It should return a boolean that indicates whether to add the entry to the state.

Release History

  • 1.1.1
    • Support returning multiple entries in the polling callback
    • Support reset action to reset the state
    • Remove initialPolling callback (can be handled in the polling callback by the user)
  • 1.0.0
    • First stable version

Meta

Naor Ye – [email protected]

Distributed under the MIT license. See LICENSE for more information.

https://github.com/naorye/redux-polling

Contributing

  1. Fork it (https://github.com/naorye/redux-polling/fork)
  2. Create your feature branch (git checkout -b feature/fooBar)
  3. Commit your changes (git commit -am 'Add some fooBar')
  4. Push to the branch (git push origin feature/fooBar)
  5. Create a new Pull Request