npm package: @sterensoftware/rdx
Description: RDX is a small Redux library of "higher-order reducers" (and a couple utilities).  It began life as a single helper function to enable writing more declarative code.
Author: Copyright
Latest version: 0.4.1

# RDX

RDX is a small Redux library of "higher-order reducers" (and a couple utilities).  It began life as a single helper function to enable writing more declarative code.

RDX also embraces separating `state` from the "functional core" of application business logic.

---

## Installation

```
npm install --save @sterensoftware/rdx
```

## Available named imports

## `reduceConditionally`

```
reduceConditionally({
	when: (state, action) => boolean,
	with: <reducer>,
	[otherwise: <default reducer>]
})
```

`reduceConditionally`, which simply returns existing state by default, supports Redux's fundamental paradigm of well-defined state transitions by allowing state to change only under explicit conditions. Overriding the default behavior is also possible (by providing an `otherwise` reducer), when necessary.

## `reduceOnActionType`

```
reduceOnActionType({
	[actionType]: <reducer>,
	...
})
```
or
```
reduceOnActionType({
	[actionType]: <reducer>,
	...
}, <default reducer>)
```

`reduceOnActionType` builds reducer functionality for a single piece of `state` by declarative composition of simple reducers.

In other words, it reduces cognitive load (and supports Separation of Concerns) by allowing each action to be reduced independently, enhances readability by "labeling" each reducer with an `action.type`, and encourages declarative programming by obsoleting the imperative Big Giant Switch.

## `reduceObjectProperties`

```
reduceObjectProperties(
	{
		reducePropertyName: (state, action) => string,
		reducePropertyValue: <reducer>
	},
	...
)
```

`reduceObjectProperties` will run all reducers passed to it (in order) as long as the prior state is not `undefined` or `null`.  It will reduce each property of the exisiting `state` as specified: `reducePropertyName` indicates which property to set with the value returned by `reducePropertyValue`.  Any properties not specified will remain unchanged.  If `reducePropertyValue` returns `undefined` the property will be `delete`d from the object.

(Please note, returning a static string value from each `reducePropertyName` method approximates Redux's `combineReducers` functionality.)

## `mapObjectPropertiesReducerParameters`

```
mapObjectPropertiesReducerParameters({
	reducePropertyName: string?,
	reducePropertyValue: string?
})
```

`mapObjectPropertiesReducerParameters` will produce a function analogous to `reduceObjectProperties` while allowing all respective reducers to be named by the developer.  For example:
```
const reduceObjectProperties = mapObjectPropertiesReducerParameters({
	reducePropertyName: 'which',
	reducePropertyValue: 'with'
})

...

reduceObjectProperties(
	{
		which: (state, action) => string,
		with: <reducer>
	},
	...
)
```

_In 0.4.0, `mapObjectPropertiesReducerParameters` replaced `makeObjectPropertiesReducerFactory`.  Please also note the new parameter names when migrating._

## `reducePropertyFromAction`

```
reducePropertyFromAction(<action property name>)
```
or
```
reducePropertyFromAction(action => <new state>)
```

`reducePropertyFromAction` is a small helper function for building a reducer that simply returns the given property directly from the `action`.  It is included for convenience.

_Since 0.3.1:_

To support better readability (via consistency), `reducePropertyFromAction` will also accept a function that returns new `state`.

_**Please note:** The function provided here is **not a reducer**; it will be invoked with the `action` as its first and only parameter._

## `reduceArrayElements`

```
reduceArrayElements({
	when: (state, action) => boolean,
	with: <reducer>,
})
```

`reduceArrayElements` enables updating only the specified element(s) of a state collection (an `array`).  To add or remove item(s) see respectively `appendToArray` or `removeFromArray`, below.

(Please note, this function is only supported for `array` state.)

## `appendToArray`

```
appendToArray({ with: (state, action) => <value(s) to append> })
```

`appendToArray` enables growing a state collection by one or more items.  If your reducer returns an `array` of values then the state returned will be a concatenation of the existing state and those values.  To append an `array` to state, simply wrap it with an outer `array`.

(Please note, this function is only supported for `array` state.)

## `removeFromArray`

```
removeFromArray({ when: (element, action, index) => boolean })
```

`removeFromArray` will drop any elements from state for which your function returns `true`.

(Please note, this function is only supported for `array` state.)

## `withDefaultInitialState`

```
withDefaultInitialState(<initial state>, <reducer>)
```

`withDefaultInitialState` allows setting default initial state for an _existing_ reducer (similar to an argument default when defining an new reducer, e.g. `(state = defaultInitalState, action) => { ... }`).

## `replace`

```
replace({ with: <replacement> })
```
or
```
replace({ with: (state, action) => <replacement> })
```

`replace` returns a reducer that always returns the `replacement`.

If `with` is a `function`, it will simply be returned.  This is to support programatic replacement while preserving readability.

## `keepExistingState`

```
(state, action) => state
```

`keepExistingState` is a reducer that simply returns existing state.  It is included to aid readability.

## `remove`

`remove` is a do-nothing reducer that simply returns `undefined`.  It is included to aid readability when using RDX, but be warned: it is not compatible with out-of-the-box Redux, which intentionally doesn't support reducers returning `undefined` _(and if you're a Redux maintainer reading this and thinking "maybe?", please don't break your existing `undefined` paradigm to accomplish something like this silly `remove`)_.