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

v1.0.0

Published

An opinionated set of utilities to make redux applications easier to maintain.

Downloads

2

Readme

Redux-adjunct

An opinionated set of utilities to make redux applications easier to maintain. Redux-adjunct reduces the boilerplate required to write reducers and encourages developers to organize their code around features instead of splitting code based on technical details.

It encourages functional programming by exporting only pure and curried functions.

Motivation

Redux is a great tool, too often underestimated. Recently, we've seen many people move away from Redux, as it has a reputation for being cumberstone and hard to get into. The boilerplate required to create action types, actions and reducers can be frustrating. This is attempt at reducing this boilerplate by providing a set of simple tools that make writing Redux apps faster. It also enforces correctness and documentation for actions and action types.

I belive concision is its own reward, so the library is highly motivated by the satisfaction of being able to write reducers in very few lines.

Install

npm install redux-adjunct
yarn add redux-adjunct

Write action creators and enforce corectness

Redux-adjunct allows you to create namespaced action types and their associated action creators in a single line.

import { createAction } from 'redux-adjunct';

// All actions related to a single feature are namespaced so they can be eaily debugged using devtools
const action = createActionSpec('user');

const [SET_USERNAME, setUsername] = createAction('SET_USERNAME');
const [SET_EMAIL, setEmail] = createAction('SET_EMAIL');

setUsername('gbogard') // => { type: 'user.SET_USERNAME', payload: 'gbogard' }

Validating the payload of your actions

In a weakly typed language like Javacript, it's common to forget a property or to put a number in place of a string. Redux-adjunct can enforce payload correctness at runtime to catch most of those errors during development. Note that this feature is completely opt-in.

The createActionSpec function works just like createAction, except it accepts one more argument in the form of a predicate. You need to provide a function that given the action's payload will return either true or false to indicate whether the payload is correct. You can put any validation logic you'd like, put redux-adjunct provides several ready to use predicates for you.

import { createActionSpec, isNumber, isString } from 'redux-adjunct';

const action = createAction('user');

// Age must be a number
const [SET_AGE, setAge] = createAction('SET_AGE', isNumber);

// Username must be a string
const [SET_USERNAME, setUsername] = createAction('SET_USERNAME', isString);

setUsername('gbogard') // => { type: 'user.SET_USERNAME', payload: 'gbogard' }
setUsername(42) // Throws an exception in development mode

Redux-adjunct provides a helpful hasShape predicate that can enforce a predicate for each key of an object.

import { createActionSpec, isNumber, isString, hasShape } from 'redux-adjunct';

const action = createAction('user');
const [SET_USER, setUser] = createAction('SET_USER', hasShape({
  username: isString,
  age: isNumber,
}));

Combining predicates with logical combinators

Redux-adjunct provide and and or functions that allows you to combine predicates into a single one.

import { createActionSpec, hasShape, isNumber, isUndefined, or } from 'redux-adjunct';

const action = createAction('user');
const [SET_USER, setUser] = createAction('SET_USER', hasShape({
  age: or(isNumber, isUndefined), // Age is optional
}));

Redux-adjunct comes with various types predicates like isString, isFunction, isBoolean that also come in the form isStringOrUndefined, isFunctionOrUndefined, isBooleanOrUndefined.

and allows you to specify multiple requirements for your payload

import { createActionSpec, isString, hasMinlength, and } from 'redux-adjunct';

const action = createAction('user');
const [SET_USERNAME, setUserName] = createAction('SET_USERNAME', and(isString, hasMinlength(8)));

Write concise reducers with less effort

A reducer is merely a function that takes an action and the current state and returns a new state. The logic inside a reducer can be anything as long as the function remains pure. Howevwer, a very common pattern in Redux is to switch over the action's type and return the appropriate state for each action :

const initialState = {
  isOpen: false,
}

function myReducer(state = initialState, { type, payload }) {
  switch (type) {
    case OPEN:
      return { ...state, isOpen: true };
    default:
      return state;
  }
}

Redux-adjunct allows you to write reducers as a map from action types to pure functions, elminating the need for the verbose switch syntax.

import { createReducer, setter } from 'redux-adjunct';

const initialState = {
  isOpen: false,
}

const myReducer = createReducer(initialstate, {
  [OPEN]: state => ({ ...state, isOpen: true }),
})

Functions in reducers receive both the current state and the payload of the action as arguments.

Combined with a functional programming library like Ramda, you get the ability to write powerful transforms in a very clean and concise manner :

import { createReducer, setter } from 'redux-adjunct';
import { evolve, not } from 'ramda';

const initialState = {
  isOpen: false,
}

const myReducer = createReducer(initialstate, {
  [TOGGLE]: evolve({ isOpen: not }),
})

In this case, evolve({ isOpen: not }) is equivalent to state => ({ ...state, isOpen: !state.isOpen }).

Setters

The setter method returns a method that, given a state and a payload, will set a single property of your state to the payload. Its signature allows for direct use in reducers created with createReducer.

You can use it on a top-level property :

createReducer(initialstate, {
  [SET_PROFILE]: setter('profile')
})

Or you can update a path :

createReducer(initialstate, {
  [SET_USERNAME]: setter('profile', 'details', 'username')
})

Note that when dealing with arrays you can also use the index of the element you wish to update.

Focus on features

Through concision, redux-adjunct enables to put action types, action creators and reducers together in a single file based on the feature they relate to. This allows to think in a feature-centric way, where instead of having a hierarchy that looks like this :

- actionCreators
--- users
--- pictures
--- videos
- actionTypes
--- users
--- pictures
--- videos
- reducers
--- users
--- pictures
--- videos

You can make your file structure look like this :

- users
- pictures
- videos

No more folding and unfolding to see all your files when your application grows. Everything is at the write place. This encourages developers to think of features as self-sufficient modules that can be taken in or out at any given time.

Running tests

npm run test