
Research
/Security News
npm Author Qix Compromised via Phishing Email in Major Supply Chain Attack
npm author Qix’s account was compromised, with malicious versions of popular packages like chalk-template, color-convert, and strip-ansi published.
redux-pending-middleware
Advanced tools
A redux middleware which tracks your asynchronous Redux actions (effects) and informs about the progress through selector function
A redux middleware which tracks your asynchronous redux actions (effects) and informs about the progress through selector function.
List of supported libraries that process redux effects:
It's worth mention that redux-pending-middleware
allows you to code simultaneously with all the above libraries simultaneously.
Have you ever been in a situation where you need to add a global loader/spinner to any side effect that you process using third-party libraries such as Redux and some kind of library for asynchronous processing, for example, redux-saga / redux-thunk / promise middlewares?
Why is that bad?
Well, redux-pending-middleware
does this from scratch:
redux-saga
and redux-toolkit
redux-thunk
in the matters of side effects (not actions chaining) and redux-promise-middleware
(essentially uses it out of the box)npm install redux-pending-middleware
redux-pending-middleware
provides its own state for storing active effects (pending promise phase).
import { combineReducers } from 'redux';
import { insertPending } from 'redux-pending-middleware';
import { planetReducer as planet } from './planetReducer';
import { universeReducer as universe } from './universeReducer';
export const rootReducer = combineReducers(
insertPending({
planet,
universe
})
);
Depending on what you use in the project, import into the project. Now let's dwell on this in more detail.
This approach is simplest and clear. Just add the middleware and use your regular toolkit async actions as usual.
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import { reduxPendingToolkitMiddleware } from 'redux-pending-middleware';
import { rootReducer as reducer } from './root.reducer';
const defaultMiddlewares = getDefaultMiddleware();
const middleware = [reduxPendingToolkitMiddleware, ...defaultMiddlewares];
export const store = configureStore({ reducer, middleware });
If your project uses redux-saga
no additional configuration needed.
This approach is that you need to wrap the saga worker. This allows to track the start and the end of each effect.
import { trackWorker } from 'redux-pending-middleware';
import { call, put, takeEvery } from '@redux-saga/core/effects';
function* getPlanets() {
yield takeEvery(getPlanetsRequest.type, trackWorker(handleGetPlanets));
}
function* handleGetPlanets() {
const planets = yield call(Api.getPlanets);
yield put(getPlanetsCompleted(planets));
}
This approach successfully combined with custom wrappers on top of the worker, for example, error handling.
const workerWrapper = worker => {
return trackWorker(customWrapper);
function* customWrapper(...args) {
try {
yield* worker(...args);
} catch (error) {
yield put(setFetchError(error));
}
}
};
Ok, here I need to explain the problem a bit
It’s not entirely true this package supports redux-thunk
, but the truth is that you can forward promises to payload.
That is the way redux-promise-middleware
does. At the moment, this library completely replaces redux-promise-middleware
.
In the plans, through the collaboration, expand the API of redux-promise-middleware
in order to reuse their code.
For details, you can go to read the documentation of redux-promise-middleware
about how this works.
In short, everything is quite simple.
You pass Promise as payload and we will have stateful types inside the reducer.
Let's say we have action type GET_PLANETS
, so when we call our action with a type and a promise in the payload, it first triggers a reducer with GET_PLANETS_PENDING
.
Then, when our promise resolved, we will have GET_PLANETS_FULFILLED
type inside the reducer, and a value of resolved promise as a payload.
But, if an error occurs in our promise, then we get the type GET_PLANETS_REJECTED
with a reason within property payload.
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import { reduxPendingPromiseMiddleware } from 'redux-pending-middleware';
import { rootReducer as reducer } from './root.reducer';
const defaultMiddlewares = getDefaultMiddleware();
const middleware = [reduxPendingPromiseMiddleware, ...defaultMiddlewares];
export const store = configureStore({ reducer, middleware });
/**
* somewhere in the /src
* saga usage example with trackWorker
*/
function getPlanets() {
return {
type: 'GET_PLANETS',
payload: fetch('planets')
};
}
For everything to work at the same time, you need to use all the previous steps
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import {
reduxPendingPromiseMiddleware,
reduxPendingToolkitMiddleware,
trackWorker
} from 'redux-pending-middleware';
import createSagaMiddleware from '@redux-saga/core';
import { call, put, takeEvery } from '@redux-saga/core/effects';
import { rootReducer as reducer } from './root.reducer';
import { rootSaga } from './root.saga';
const defaultMiddlewares = getDefaultMiddleware();
const sagaMiddleware = createSagaMiddleware();
const middleware = [
reduxPendingPromiseMiddleware,
reduxPendingToolkitMiddleware,
sagaMiddleware,
...defaultMiddlewares
];
export const store = configureStore({ reducer, middleware });
sagaMiddleware.run(rootSaga);
/**
* somewhere in the /src
* saga usage example with trackWorker
*/
function* getPlanets() {
yield takeEvery(getPlanetsRequest.type, trackWorker(handleGetPlanets));
}
function* handleGetPlanets() {
const planets = yield call(Api.getPlanets);
yield put(getPlanetsCompleted(planets));
}
Just a regular usage of redux selectors
import React from 'react';
import { useSelector } from 'react-redux';
import { selectIsPending } from 'redux-pending-middleware';
import { YourApplication } from './YourApplication';
import { AppLoader } from './App.loader';
export const App = () => {
const isPending = useSelector(selectIsPending);
return isPending ? <AppLoader /> : <YourApplication />;
};
Contributions are welcome. For major changes, please open an issue first to discuss what you would like to change.
If you made a PR, make sure to update tests as appropriate and keep the examples consistent.
Please reach me out if you have any questions or comments.
I find these packages useful and similar for this one. So, it's important to mention them here.
The main reason why I didn’t choose them: they do one thing, and it’s impossible to add something second to them.
This project is MIT licensed.
FAQs
A redux middleware which tracks your asynchronous Redux actions (effects) and informs about the progress through selector function
The npm package redux-pending-middleware receives a total of 0 weekly downloads. As such, redux-pending-middleware popularity was classified as not popular.
We found that redux-pending-middleware 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.
Research
/Security News
npm author Qix’s account was compromised, with malicious versions of popular packages like chalk-template, color-convert, and strip-ansi published.
Research
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
Security News
Ruby maintainers from Bundler and rbenv teams are building rv to bring Python uv's speed and unified tooling approach to Ruby development.