riducers
v2.0.1
Published
Plug-and-play Redux reducers for entity-based state management. Supports list, map, mapList, and static state types with built-in insert, delete, replace, sort, and clear actions.
Downloads
254
Readme
riducers
Plug-and-play Redux reducers for entity-based state management. Supports four state types optimized for different use cases.
Installation
npm install riducersState Types
| Type | State Shape | Best For |
|------|-------------|----------|
| list | ModelObj[] | Ordered collections |
| map | { [id]: ModelObj } | Fast lookups by ID |
| mapList | { [key]: ModelObj[] } | Grouped/categorized data |
| static | ModelObj \| null | Single objects (auth, settings) |
Quick Start
import { configureStore } from '@reduxjs/toolkit'
import { reducerBuilder } from 'riducers'
const store = configureStore({
reducer: {
users: reducerBuilder('users', { stateType: 'list' }),
usersById: reducerBuilder('usersById', { stateType: 'map' }),
tasksByProject: reducerBuilder('tasks', { stateType: 'mapList', mapKeyName: 'projectId' }),
currentUser: reducerBuilder('currentUser'),
}
})1. List Reducer (stateType: 'list')
Stores entities as an ordered array. Supports: insert, unshift, replace, delete, shift, sort, clear.
const usersReducer = reducerBuilder('users', { stateType: 'list' })Actions & State Transitions
// Initial state
state = []
// insert - append items
dispatch({ type: 'users/insert', payload: { id: 1, name: 'Alice' } })
state = [{ id: 1, name: 'Alice' }]
dispatch({ type: 'users/insert', payload: [{ id: 2, name: 'Bob' }, { id: 3, name: 'Carol' }] })
state = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Carol' }]
// unshift - prepend item
dispatch({ type: 'users/unshift', payload: { id: 0, name: 'Zoe' } })
state = [{ id: 0, name: 'Zoe' }, { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Carol' }]
// delete - remove by id
dispatch({ type: 'users/delete', payload: { id: 2 } })
state = [{ id: 0, name: 'Zoe' }, { id: 1, name: 'Alice' }, { id: 3, name: 'Carol' }]
// shift - remove first item
dispatch({ type: 'users/shift' })
state = [{ id: 1, name: 'Alice' }, { id: 3, name: 'Carol' }]
// sort - reorder (default: ascending by keyName)
dispatch({ type: 'users/sort' })
state = [{ id: 1, name: 'Alice' }, { id: 3, name: 'Carol' }]
// sort with custom comparator
dispatch({ type: 'users/sort', sort: (a, b) => b.id - a.id })
state = [{ id: 3, name: 'Carol' }, { id: 1, name: 'Alice' }]
// replace - replace entire state
dispatch({ type: 'users/replace', payload: [{ id: 10, name: 'New' }] })
state = [{ id: 10, name: 'New' }]
// clear - reset to initial state
dispatch({ type: 'users/clear' })
state = []With Auto-Sort
const sortedReducer = reducerBuilder('users', {
stateType: 'list',
sort: (a, b) => a.name.localeCompare(b.name)
})
dispatch({ type: 'users/insert', payload: [{ id: 1, name: 'Zoe' }, { id: 2, name: 'Alice' }] })
state = [{ id: 2, name: 'Alice' }, { id: 1, name: 'Zoe' }] // auto-sorted2. Map Reducer (stateType: 'map')
Stores entities keyed by ID for O(1) lookups. Supports: insert, replace, delete, clear.
const usersReducer = reducerBuilder('users', { stateType: 'map' })Actions & State Transitions
// Initial state
state = {}
// insert - add/update items
dispatch({ type: 'users/insert', payload: { id: 1, name: 'Alice' } })
state = { 1: { id: 1, name: 'Alice' } }
dispatch({ type: 'users/insert', payload: [{ id: 2, name: 'Bob' }, { id: 3, name: 'Carol' }] })
state = {
1: { id: 1, name: 'Alice' },
2: { id: 2, name: 'Bob' },
3: { id: 3, name: 'Carol' }
}
// insert updates existing item
dispatch({ type: 'users/insert', payload: { id: 1, name: 'Alice Updated' } })
state = {
1: { id: 1, name: 'Alice Updated' },
2: { id: 2, name: 'Bob' },
3: { id: 3, name: 'Carol' }
}
// delete - remove by id
dispatch({ type: 'users/delete', payload: { id: 2 } })
state = {
1: { id: 1, name: 'Alice Updated' },
3: { id: 3, name: 'Carol' }
}
// replace - replace entire state
dispatch({ type: 'users/replace', payload: [{ id: 10, name: 'New' }] })
state = { 10: { id: 10, name: 'New' } }
// clear - reset to initial state
dispatch({ type: 'users/clear' })
state = {}Shorthand Syntax
Map reducers support using the key directly as the action type:
// Insert/update using key as action type
dispatch({ type: 'users/123', payload: { name: 'Alice' } })
state = { 123: { id: 123, name: 'Alice' } }
// Delete by dispatch with no payload
dispatch({ type: 'users/123', payload: null })
state = {}3. MapList Reducer (stateType: 'mapList')
Groups entities into keyed arrays—ideal for categorized data. Requires mapKeyName. Supports: insert, unshift, replace, delete, shift, sort, clear.
const tasksReducer = reducerBuilder('tasks', {
stateType: 'mapList',
keyName: 'id',
mapKeyName: 'projectId',
initialState: {}
})Actions & State Transitions
// Initial state
state = {}
// insert - items grouped by mapKeyName
dispatch({ type: 'tasks/insert', payload: { id: 1, projectId: 'a', title: 'Task 1' } })
state = {
a: [{ id: 1, projectId: 'a', title: 'Task 1' }]
}
dispatch({ type: 'tasks/insert', payload: [
{ id: 2, projectId: 'a', title: 'Task 2' },
{ id: 3, projectId: 'b', title: 'Task 3' }
]})
state = {
a: [{ id: 1, projectId: 'a', title: 'Task 1' }, { id: 2, projectId: 'a', title: 'Task 2' }],
b: [{ id: 3, projectId: 'b', title: 'Task 3' }]
}
// delete - items removed across all groups, empty groups removed
dispatch({ type: 'tasks/delete', payload: { id: 3 } })
state = {
a: [{ id: 1, projectId: 'a', title: 'Task 1' }, { id: 2, projectId: 'a', title: 'Task 2' }]
}
// sort - sorts within each group
dispatch({ type: 'tasks/sort', sort: (a, b) => b.id - a.id })
state = {
a: [{ id: 2, projectId: 'a', title: 'Task 2' }, { id: 1, projectId: 'a', title: 'Task 1' }]
}
// shift - removes first item from each group
dispatch({ type: 'tasks/shift' })
state = {
a: [{ id: 1, projectId: 'a', title: 'Task 1' }]
}
// replace - replace entire state
dispatch({ type: 'tasks/replace', payload: [{ id: 10, projectId: 'x', title: 'New' }] })
state = {
x: [{ id: 10, projectId: 'x', title: 'New' }]
}
// clear - reset to initial state
dispatch({ type: 'tasks/clear' })
state = {}4. Static Reducer (default)
Stores a single object or null. Supports: insert, replace, delete, clear.
const authReducer = reducerBuilder('auth')Actions & State Transitions
// Initial state
state = null
// insert - set the object
dispatch({ type: 'auth/insert', payload: { userId: 1, token: 'abc123' } })
state = { userId: 1, token: 'abc123' }
// replace - replace entire object
dispatch({ type: 'auth/replace', payload: { userId: 2, token: 'xyz789' } })
state = { userId: 2, token: 'xyz789' }
// delete - set to null
dispatch({ type: 'auth/delete' })
state = null
// clear - reset to initial state
dispatch({ type: 'auth/clear' })
state = nullOptions
interface ReducerOpts {
stateType?: 'list' | 'map' | 'static' | 'mapList' // default: 'static'
keyName?: string // ID field name, default: 'id'
mapKeyName?: string // Required for mapList - key to group by
sort?: SortFn // Auto-sort on insert
initialState?: any // Custom initial state
}Full Store Example
import { configureStore } from '@reduxjs/toolkit'
import { reducerBuilder } from 'riducers'
const store = configureStore({
reducer: {
// Ordered list of posts
posts: reducerBuilder('posts', { stateType: 'list' }),
// Users indexed by ID for quick lookup
users: reducerBuilder('users', { stateType: 'map' }),
// Comments grouped by postId
comments: reducerBuilder('comments', {
stateType: 'mapList',
mapKeyName: 'postId',
initialState: {}
}),
// Current authenticated user
auth: reducerBuilder('auth'),
}
})
// After some dispatches, state might look like:
// {
// posts: [
// { id: 1, title: 'Hello World' },
// { id: 2, title: 'Redux Tips' }
// ],
// users: {
// 1: { id: 1, name: 'Alice' },
// 2: { id: 2, name: 'Bob' }
// },
// comments: {
// 1: [
// { id: 101, postId: 1, text: 'Great post!' },
// { id: 102, postId: 1, text: 'Thanks!' }
// ],
// 2: [
// { id: 201, postId: 2, text: 'Very helpful' }
// ]
// },
// auth: { userId: 1, token: 'abc123' }
// }License
MIT
