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

v2.2.4

Published

This a Redux utilities library for alternate approaches to creating all the redux boilerplate. It uses ramda under the hood for most of the utilities.

Downloads

22

Readme

Redux Utility Toolbelt

This a Redux utilities library for alternate approaches to creating all the redux boilerplate. It uses ramda under the hood for most of the utilities.

Install

yarn add redux-utility
# or
npm install redux-utility

Migration from 1.x to 2.x

Since exports were reorganized, all that is needed is to update exports. Change this

import { Reducers } from 'redux-utility'

const { createReducer } = Reducers;

to

import { createReducer } from 'redux-utility'

Usage

The functions in the library are divided into 6 categories:

  • Actions
  • Hooks
  • Reducers
  • Redux
  • Observable
  • Modules

Every function inside each module is exported as a named export. A plan for rxjs like imports is on the way

Actions

The Actions object contains functions for creating action creators.

import { 
    nullaryAction,
    unaryActionCreator,
    nAryActionCreator,
    shape
} from 'redux-utility'

nullaryActionCreator

Creates an action creator with no arguments, given the type

const inc = nullaryActionCreator("INC")
inc() // returns { type: "INC" }

unaryActionCreator

Creates an action creator that receives a single argument, given the type

const withPayload = unaryActionCreator("WITH_PAYLOAD");
withPayload(42) // returns { type: "WITH_PAYLOAD" , payload: 42 }

nAryActionCreator

Creates an action creator given the type and a payload constructor. Payload is constructed by calling the payload function with the given arguments

const withTwoArgs = nAryActionCreator("ADD",(a,b) => ({ a,b }))
withTwoArgs(20,22) // returns { type: "ADD" , payload: { a: 20, b: 22 } }

shape

Shape is a simple utility added for the most common case shape receives the names of the object keys and returns a function that constructs objects based on argument position

const ABShape = shape('a','b')
ABShape(1,2) // returns { a: 1, b: 2 }

const withAB = nAryActionCreator("ADD", ABShape)
withAB(20,22) // returns { type: "ADD" , payload: { a: 20, b: 22 } }

Hooks

import { 
    usePathSelector 
} from 'redux-utility'

usePathSelector

The hook receives a dot separated path and a default value and returns a piece of state

// state = { a : { b: { c: 42 } } }

usePathSelector("a.b.c") // returns 42
usePathSelector("a.b.d") // returns undefined
usePathSelector("a.b.d",50) // returns 50

Reducers

Contains various functions that create reducers through different styles

import { 
    createReducer,
    createPairsReducer, 
    createEventReducer  
} from 'redux-utility'

createReducer

Receives a configuration object and creates a reducer based on the object. Uses the keys as action types and calls the value associated with the key. Also a special 'default' key is reserved for when no action is handled. The default value for the default key is the identity function

const DEC = 'DEC'
const INC = 'INC'

const reducer = createReducer({
    [DEC]: (state,action) => state - 1,
    [INC]: (state,action) => state + 1,
    // default: (state) => state
})

const dec = nullaryActionCreator(DEC)
const inc = nullaryActionCreator(INC)

reducer(5,dec()) // returns 4
reducer(5,inc()) // returns 6
reducer(5, {type: "anything"}) // returns 5

createPairsReducer

Creates a reducer based on an array of (actionType, function) pairs. Converts the array to an object and calls createReducer. Keep in mind that the array is not validated and must conform to a valid object.

const DEC = 'DEC'
const INC = 'INC'

const reducer = createPairsReducer([
    [DEC, (state,action) => state - 1],
    [INC, (state,action) => state + 1],
    // ["default", (state) => state]
])

const dec = nullaryActionCreator(DEC)
const inc = nullaryActionCreator(INC)

reducer(5,dec()) // returns 4
reducer(5,inc()) // returns 6
reducer(5, {type: "anything"}) // returns 5

createEventReducer

Creates a reducer based on a function that receives an object with a similar interface of that of NodeJS Event Emitters, where events are action types. Has a default event for handling the default case.

const DEC = 'DEC'
const INC = 'INC'

const reducer = createEventReducer(reducer =>
    reducer.on(DEC, (state,action) => state - 1)
    reducer.on(INC, (state,action) => state + 1)
    // reducer.on("default", (state) => state)
])

const dec = nullaryActionCreator(DEC)
const inc = nullaryActionCreator(INC)

reducer(5,dec()) // returns 4
reducer(5,inc()) // returns 6
reducer(5, {type: "anything"}) // returns 5

Redux

Contains general redux utilities

import {
    getDevtoolsCompose
} from 'redux-utility'

getDevtoolsCompose

Returns the redux devtools compose if it exist. Otherwise returns redux compose. The function may receive an argument that when false, forces the function to return redux's compose. This could be a function or a boolean value. Common usage:

const shouldUseDevtool = () => process.env.NODE_ENV === "development"
const composeEnhancers = getDevtoolsCompose(shouldUseDevtool)

const store = createStore(
    reducer,
    initialState,
    composeEnhancers(...enhancers)
)

Observable

Contains utilities to use with redux-observable

import {
    fromActions,
    fromActionsEager
} from 'redux-utility'

fromActions

Creates an observable creator function from the given action creators. The observable created emits the actions in the given order by passing the given arguments to the action creators. Useful when a piece of state is needed or the actions have a payload. When the emitted actions have no needed payload, it is commonly better to use the eager version of this utility.

const DEC = 'DEC'
const INC = 'INC'

const reducer = createReducer({
    [DEC]: (state,action) => state - action.payload,
    [INC]: (state,action) => state + action.payload,
})

const inc = unaryActionCreator("INC")
const dec = unaryActionCreator("DEC")

const obs = fromActions( inc, dec )(5)
// --- inc(5) --- dec(5) |--->

// Common usage
const epic = actions$ => actions$.pipe(
    ofType("START"),
    map(() => 5)
    mergeMap(
        fromActions(
            inc,
            dec
        ) // returns the same as fromActions( inc, dec )(5)
    )
)

fromActionsEager

Eager version of fromActions. Creates an action observable from the given action creators by calling them with no arguments. Similar to calling rxjs Observable.from with an array of actions.

const DEC = 'DEC'
const INC = 'INC'

const reducer = createReducer({
    [DEC]: (state,action) => state - 1,
    [INC]: (state,action) => state + 1,
})

const inc = nullaryActionCreator("INC")
const dec = nullaryActionCreator("DEC")

const obs = fromActionsEager( inc, dec )
// --- inc() --- dec() |--->

// Common usage
const epic = actions$ => actions$.pipe(
    ofType("START"),
    mergeMap(() =>
        fromActionsEager(
            inc,
            dec
        ) // returns the same as fromActionsEager( inc, dec )
    )
)

Modules

Contains common use cases ready to be used. Currently contains:

  • createAsyncState

createAsyncState

Common pattern for async state. creates a fetch, success, and error action with their respective constants, reducer function, reducer config, reducer register function, reducer pairs config and reducer initial state. The usage is as follows:

import { createAsyncState } from 'redux-utility';

// Basic usage
// receives a key for namespacing the constants. The constants will be prefixed with the key
const reducer = createAsyncState("user");

// optionally, if you want the state to be nested inside the key provided
const nested = createAsyncState("user",{ nested: true });

export default reducer;

export const {
    fetch: FETCH_USER,
    success: USER_SUCCESS,
    error: USER_ERROR
} = reducer.constants;

export const {
    fetch: fetchUser,
    success: userSuccess,
    error: userError
} = reducer.actions;

// more options added for flexibility

createReducer(reducer.config);
createPairsReducer(reducer.pairs);
createEventReducer(reducer.register);

// mixing with other pieces of state

const OTHER = "OTHER";
createReducer({
    ...reducer.config,
    [OTHER]: (state) => ({ ...state, other: true }),
})
createPairsReducer([
    ...reducer.pairs,
    [OTHER, (state) => ({ ...state, other: true })]
])
createEventReducer((handler) => {
    reducer.register(handler);
    handler.on(OTHER,(state) => ({ ...state, other: true }))
})

// extension of reducer

const async = createAsyncState("auth")
const extendedReducer = async.extend({
    success: (state,action) => {
        return {
            ...state,
            authenticated: true
        }
    }
})

// or the long way around
const extended = createReducer({
    [aync.constants.success]: async.extend.success((state,action) => {
        return {
            ...state,
            authenticated: true
        }
    }),
})

// this are the possible states

const initialState = reducer.initialState

// {
//     loading: false,
//     data: undefined,
//     error: undefined
// }

dispatch(fetchUser())

// {
//     loading: true,
//     data: undefined,
//     error: undefined
// }

dispatch(userSuccess({ name: "User" }))

// {
//     loading: false,
//     data: { name: "user" },
//     error: undefined
// }

dispatch(userError("Something went wrong"))

// {
//     loading: false,
//     data: undefined,
//     error: "Something went wrong"
// }