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-notification-enhancer

v1.0.6

Published

Enhancer for Redux allowing to throttle and manually control notifications to subscribers

Downloads

23

Readme

Redux Notification Enhancer

by Vytenis Urbonavičius

Redux Notification Enhancer (RNE) drastically improves performance of some Redux-based applications by providing control over subscriber notifications after state updates.

Main features:

  • Notification throttling - if enabled, it makes sure that subscribers are allowed to finish handling state changes before a new notification is triggered. By default Redux is notifying all subscribers on every state change. Most of the time it does not require a significant effort to introduce throttling with RNE into an existent project.
  • Manual notification control - when used, it allows to mark certain actions as passive - they would update state but avoid notifying subscribers. When introducing manual notification control into existent project, it can be done gradually.

Above optimizations become even more impactful when used together with @reduxjs/toolkit. Its thunk operations always trigger multiple dispatches whenever actions are pending, fulfilled or rejected. If RNE is not used, these auto-generated actions are causing notifications even if they are not necessary (i.e. thunk action is only dispatching other actions).


WARNING:

RNE by design breaks default lifecycle of Redux and increases complexity of code. Only use in projects where performance is critical and cannot be achieved by other optimization techniques. Please see "Troubleshooting" section for more details.


Example use case

When using Redux with React, React performs render on every Redux notification for every single state change. If a very complex system is developed and render becomes heavy despite being well written, optimized using memoization and other techniques - it becomes important to reduce amount of renders to achieve much higher browser frame rate.

This can be achieved by:

  • Enabling throttling and making sure that browser draws frames between renders.
  • Identifying actions which should not cause render all by themselves and marking them as passive.

Integration

Simplest way to include RNE into Redux is by passing it as a second argument to createStore.

const {createNotificationEnhancer} = require('redux-notification-enhancer')
// See "Options" to see what "options" argument may contain
const {enhancer} = createNotificationEnhancer(options)
const store = createStore(reducers, enhancer)

If you need other enhancers such as applyMiddleware, you can provide them using compose() function provided by Redux.

const {enhancer} = createNotificationEnhancer(options)
const multipleEnhancers = compose(applyMiddleware(thunk), enhancer)
const store = createStore(reducers, enhancers)

Note that these days it is often advised to use @reduxjs/toolkit instead of pure Redux. In case of @reduxjs/toolkit, integration is performed using configureStore:

const {enhancer} = createNotificationEnhancer(options)

const store = configureStore({
  reducer,
  // ...
  enhancers: [enhancer],
})

Usage

RNE provides function for marking actions as "passive" or "immediate". These functions modify action "type" string by adding special prefixes.

Passive actions are actions which should modify state but should not notify subscribers.

Immediate actions are actions which should be executed at once even if throttling is enabled.

If no marker is used - action is either throttled (if throttling is enabled) or executed normally as in standard Redux without RNE.

const {enhancer, passive, immediate} = createNotificationEnhancer(options)

// Alternatively use configureStore if used with @reduxjs/toolkit
const store = createStore(reducers, enhancer)

// Throttled if throttling is enabled
store.dispatch({type: 'NORMAL_ACTION'})

// Changes state, but does not notify
store.dispatch({type: passive('STATE_CHANGE_ONLY')})

// Executed at once even if throttling is enabled
store.dispatch({type: immediate('THROTTLE_BYPASS')})

Options

Options can be provided as an optional object argument for createNotificationEnhancer. Object keys and values are explained in the table below:

| Option | Default | Meaning | | ---------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | throttle | false | Makes sure that promises of subscribers are resolved before notifying them again. | | requestAnimation | true | When throttling is enabled it requests animation frame after subscribers are notified. Should be disabled if used not on browser. | | prefixes | {passive:'S%', immediate:'I%'} | Allows changing one or all marker prefixes to custom ones. |


Response of createNotificationEnhancer

| Key | Meaning | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | enhancer | Enhancer itself to be passed to createStore of Redux | | passive | Function for modifying action type and marking that action as "passive" - only impacting state but not notifying subscribers. | | immediate | Function for modifying action type and marking that action as "immeditate" - to be executed at once even if throttling is enabled. There is no need to use this marker if throttling is disabled. | | getNotificationPromise | Returns promise of current notifications. This promise is resolved once all currently notified subscribers complete their work. There is no need to use this promise if throttling is disabled. |


Example use case for getNotificationPromise:

If React is used together with Redux and RNE with throttling enabled, React renders may happen slightly later than expected. To ensure that last render has completed before further operations, getNotificationPromise can be used:

// Perform some code which causes render here
// ...
await getNotificationPromise()
// ...
// Perform code which needs to read DOM or depend on render in some other way here

Troubleshooting

Problem:

State changes are not reflected in another part of the application (React-based UI for example).

Solution:

  • Make sure your actions are not marked as passive.
  • If using on browser, make sure that requestAnimation option is enabled.

Problem:

My actions trigger notifications too rarely (causing lagging animations for example).

Solution:

When throttling is used, notifications are delayed until all subscribers complete their work. In many cases this improves performance drastically. However, in some cases actions do not need to wait for all subscribers - you can try adding exceptions for certain actions by marking them as "immediate".


Problem:

Subscribers are notified often causing lag and excessive calculations.

Solution:

RNE throttling is designed to tackles this issue. However, it is disabled by default. Make sure you enable throttling feature by passing a "throttle" flag as "true".


Problem:

I am using React and my code depends on DOM which should change after dispatching an action. However, DOM does not change immediately after dispatching that action when using RNE.

Solution:

Request last render promise using getNotificationPromise and wait for it to resolve before performing operations on DOM.


Happy Hacking!!!