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

v1.0.1

Published

redux HigherOrderMiddleware

Downloads

12

Readme

redux-hom

redux HigherOrderMiddleware

npm version

Installation

npm install --save redux-hom

Usage

define middleware

const { applyMiddleware } = require('redux');
const { higherOrderMiddleware } = require('redux-hom');

const services = [{
    id: 'featureA',
    middleware: featureMiddlewareA
}, {
    id: 'featureB',
    middleware: featureMiddlewareB
}];

export default applyMiddleware(
    ...middlewares,
    higherOrderMiddleware({ services })
);

define action

const normalAction = {
    type: 'DO_NORMAL'
};

const featureAction = {
    type: 'NEED_SOME_FEATURE',
    $featureA: []
};

const multiFeatureAction = {
    type: 'NEED_MULTI_FEATURE',
    $featureA: [],
    $featureB: []
};

if you want diy match

const services = [{
    id: 'featureA',
    middleware: featureMiddlewareA,
    match: (action, id) => new RegExp(`:${id}`).test(action.type)
}]

const action = {
    type: 'ACTION:featureA:featureB'
}

service example


// const action = {
//     type: 'test',
//     $storage: 'someKey',
//     data: 'someValue'
// }
const storageMiddleware = store => next => action => {
  console.log(`storage ${action['$storage']}`, action.data);
  // localStorage.setItem(action['$storage'], action.data);
  return next(action);
};


// const action = {
//   type: 'test',
//   $batch: ['step-1', 'step-2']
// };
const easyBatchMiddleware = store => next => action => {
  const nextAction = next(action);
  const { $batch }= action;
  $batch.map(child => {
    store.dispatch({
      type: `${action.type}:${child}`
    });
  });

  return nextAction;
};

// const action = {
//   type: 'test',
//   $batch:  [
//     'step-1',
//     action => ({ type: `${action.type}:left` }),
//     async action => {
//       function timeout(ms) {
//         return new Promise(resolve => setTimeout(resolve, ms));
//       }
//       const asyncFunc = () => new Promise((resolv, reject) => {
//         setTimeout(
//           resolv({
//             type: `${action.type}:async`
//           })
//           , 2000);
//       });
//       const asyncAction = await asyncFunc();
//       return asyncAction;
//     }
//   ]
// };
const batchMiddleware = store => next => action => {
  const AsyncFunction = (async () => {}).constructor;
  const nextAction = next(action);
  const { $batch }= action;
  $batch.forEach(child => {
    switch (typeof child) {
    case 'string': store.dispatch({ type: `${action.type}:${child}`}); break;
    case 'function':
      if (child instanceof AsyncFunction) {
        child(action).then(asyncAction => store.dispatch(asyncAction));
      } else {
        store.dispatch(child(action));break;
      }
    default: break;
    };
  });

  return nextAction;
};

const services = [{
  id: 'storage',
  middleware: storageMiddleware
}, {
  id: 'batch',
  middleware: batchMiddleware
}];


// axios fetch
export const fetchMiddleware = store => next => action => {
  const {
    requestBody,
    onSuccess = (...args) => ({ type: `${action.type}:success`}),
    onError = (...args) => ({ type: `${action.type}:error`})
  } = action.$fetch;
  // server.request(requestBody)
  //   .then((...resp) => store.dispatch(onSuccess(...resp)))
  //   .catch((...resp) => store.dispatch(onError(...resp)))
  return next(action);
};

Why?

It's a extension for action -> middleware

here's the history

for example 1: storage case
1. you want to storage
const someFunction = value => {
  // ...
  localStorage.setItem(key, value)
}
2. you think you should use middleware
const storageMiddleware = store => next => action => {
  switch(action.type) {
  case 'LOGIN:success': localStorage.setItem('USER', JSON.stringify(action.payload.data));break;
  default:;
  }
  return next(action);
}

dispatch({ type: 'LOGIN' })
fetch().then(() => dispatch({type: 'LOGIN:success'}))
2.1 and then
const storageMiddleware = store => next => action => {
  switch(action.type) {
  case 'LOGIN:success': localStorage.setItem('USER', JSON.stringify(action.payload.data));break;
  case 'PAGE:success': localStorage.setItem('KEY', JSON.stringify(action.payload.data));break;
  case 'SOME_ACTION': ...;break;
  case '...': ...;break;
  // ...
  default:;
  }
  return next(action);
}
3 switch to regexp
const storageMiddleware = store => next => action => {
  const reg = /:success$/;
  const match = action.type.match(reg) || [];
  switch(match[1]) {
  case 'LOGIN': localStorage.setItem('USER', JSON.stringify(action.payload.data));break;
  case '...': localStorage.setItem('KEY', JSON.stringify(action.payload.data));break;
  // ...
  default:;
  }
  switch(action.type) {
  case 'SOME_ACTION': ...;break;
  default:;
  }
  return next(action);
}

const fetchSuccess = (action, data) => ({type: `${action.type}:success`, ...data})
4 implements action
const storageMiddleware = store => next => action => {
  localStorage.setItem(action.$storage, action.payload.data);
  return next(action)
}

dispatch({
  type: 'ACTION',
  $storage: 'USER',
  payload: {
    data: {}
  }
})
for more examples
import {batchActions, enableBatching} from 'redux-batched-actions';

// wrap actions
const doThing = createAction('DO_THING')
const doOther = createAction('DO_OTHER')
// wrap reducer
const store = createStore(enableBatching(reducer), initialState)
// dispatch wrapped function
dispatch(batchActions([doThing(), doOther(), 'DO_BOTH']))
// serialize in batchMiddleware

dispatch({
  type: 'DO_BOTH',
  $batch: [
    async () => ({type: 'ACTION2'}),
    async () => ({type: 'ACTION3'}),
  ]
})

import {createStore, applyMiddleware} from 'redux';
import axios from 'axios';
import axiosMiddleware from 'redux-axios-middleware';

const client = axios.create({ //all axios can be used, shown in axios documentation
  baseURL: 'http://localhost:8080/api',
  responseType: 'json'
});

let store = createStore(
  reducers, //custom reducers
  applyMiddleware(
    //all middlewares
    ...
    axiosMiddleware(client), //second parameter options can optionally contain onSuccess, onError, onComplete, successSuffix, errorSuffix
    ...
  )
)

// multi case

const client2 = axios.create({
  baseURL: 'http://localhost:8081/api',
  responseType: 'json'
})

multiClientMiddleware(
   clients, // described below
   options // optional, this will be used for all middleware if not overriden by upper options layer
 )
 
dispatch({
  type: 'FETCH_1',
  payload: {
    client: 'default',
    request:{
      url:'/categories'
    },
    onError: () => {....}
  }
});
dispatch({
  type: 'FETCH_2',
  payload: {
    client: 'default',
    request:{
    url:'/categories'
    },
    onError: () => {....}
}
})
const client1Middleware = store => next => action => {
  const {
    request,
    onSuccess = data => store.dispatch({type: `${action.type}_SUCCESS`, data}), // you can set default here
    onError = () => {...} 
  } = action.$client1;
  client1(request).then(onSuccess).catch(onError);
  return next(action);
}

dispatch({
  type: 'SOME_ACTION',
  $client1: {
    request: { url },
  },
  $client2: {
    request: { url },
  }
})

// it depends on how you write your middleware
dispatch({
  type: 'SOME_ACTION',
  $stream: [
    () => ({
      type: 'TO_CLIENT1', 
      $storageAfterFetch: 'key'
    }),
    async () => ({
      type: 'TO_CLIENT2', 
      $client2: options
    }),
    async (prev) => ({
      type: 'STORAGE_CLIENT2',
      $storage: 'key'
    })
  ]
})

Motivation

higherOrderFunction

higherOrderComponent

<Parent>
  <Child/>
</Parent>

higherOrderReducer

combineReducers({
  ...,
  combineReducers({
    ...,
  }),
})

TODO

  • more detail about usage
  • need example
  • try to merge feature like redux-batch-action or redux-pack
  • add circle ci
  • maybe something more
  • finish them & build module
  • testing common services