Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Reducer factory functions for common data structures: counters, maps, lists (queues, stacks), sets, etc.

License

NotificationsYou must be signed in to change notification settings

adrienjt/redux-data-structures

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Introduction

Redux Data Structures is a library ofreducer makers.

Reducer makers help create common reducers like counters, maps, lists (queues, stacks), sets, etc. Most application states can be built by combining a handful of these standardized building blocks.

Redux Data Structures was developed for Redux, but does not depend on it. It can actually be used with any reactive state container, even a custom one; Redux Data Structures doesn't have any dependency.

Getting Started

npm install --save redux-data-structures

Here's an example from theRedux README, rewritten with Redux Data Structures:

import{createStore}from'redux';import{counter}from'redux-data-structures';constmyCounter=counter({incrementActionTypes:['INCREMENT'],decrementActionTypes:['DECREMENT'],});conststore=createStore(myCounter);store.subscribe(()=>{console.log(store.getState());});store.dispatch({type:'INCREMENT'});// 1store.dispatch({type:'INCREMENT'});// 2store.dispatch({type:'DECREMENT'});// 1

Configuring Data Structures

Here's a more advanced example--with the same reducer maker--of a counter from 10 to 0, decreasing as a function of the action payload, then reset, representing life points for example:

import{createStore}from'redux';import{counter}from'redux-data-structures';constlifePoints=counter({initialState:10,decrementActionTypes:['PUNCH','KICK'],decrement:action=>action.value,min:()=>0,// action => numberresetActionTypes:['INSERT_COIN'],});conststore=createStore(lifePoints);store.subscribe(()=>{console.log(store.getState());});store.dispatch({type:'PUNCH',value:5});// 5store.dispatch({type:'KICK',value:7});// 0store.dispatch({type:'INSERT_COIN'});// 10

Combining Data Structures

Let's build a classic todo app with Redux Data Structures:

import{createStore,combineReducers}from'redux';import{map,set,value}from'redux-data-structures';consttodos=map({addActionTypes:['ADD_TODO'],removeActionTypes:['REMOVE_TODO'],});constcompletedTodos=set({toggleActionTypes:['TOGGLE_TODO'],removeActionTypes:['REMOVE_TODO'],keyGetter:action=>action.payload.id,});constvisibilityFilter=value({initialState:'SHOW_ALL',setActionTypes:['SET_VISIBILITY_FILTER'],valueGetter:action=>action.payload.filter,});constrootReducer=combineReducers({  todos,  completedTodos,  visibilityFilter,});conststore=createStore(rootReducer);

That's all for the store! We've relied heavily on the reducer makers' default options, which presume that:

  1. actions adhere to theFlux Standard Action (actions are plain Javascript object with atype andpayload properties),
  2. and Todos are identified by anid property, used as a key in thetodos map (and thecompletetedTodos set).

Now let's subscribe to the store and dispatch a few actions:

store.subscribe(()=>{console.log(JSON.stringify(store.getState(),null,2));});store.dispatch({type:'ADD_TODO',payload:{id:0,text:'Go fishing',},});// {//   "todos": {//     "byId": {//       "0": {//         "id": 0,//         "text": "Go fishing"//       }//     },//     "allIds": [//       0//     ]//   },//   "completedTodos": {},//   "visibilityFilter": "SHOW_ALL"// }

Notice thattodos isnormalized, for the reasons explained in the Redux documentation.

store.dispatch({type:'TOGGLE_TODO',payload:{id:0},});// {//   "todos": {//     "byId": {//       "0": {//         "id": 0,//         "text": "Go fishing"//       }//     },//     "allIds": [//       0//     ]//   },//   "completedTodos": {//     "0": true//   },//   "visibilityFilter": "SHOW_ALL"// }

Compared to the original Redux Todo example, we've separated the Todo items (id, text) from their completion state. If needed, they could be combined with aselector.

store.dispatch({type:'SET_VISIBILITY_FILTER',payload:{filter:'SHOW_COMPLETED'},});// {//   "todos": {//     "byId": {//       "0": {//         "id": 0,//         "text": "Go fishing"//       }//     },//     "allIds": [//       0//     ]//   },//   "completedTodos": {//     "0": true//   },//   "visibilityFilter": "SHOW_COMPLETED"// }store.dispatch({type:'REMOVE_TODO',payload:{id:0},});// {//   "todos": {//     "byId": {},//     "allIds": []//   },//   "completedTodos": {},//   "visibilityFilter": "SHOW_COMPLETED"// }

TheREMOVE_TODO action is reduced both by thetodos map and thecompletedTodos set.

Data Structures

So far, the following data structures have been implemented (corresponding action types are indicated in parentheses):

  • Boolean (set to true, set to false, toggle)
  • Counter (increment, decrement)
  • List (queue or stack: enqueue, dequeue, push, pop)
  • Map (add, remove, change)
  • Set (add, remove, toggle)
  • Value (set)

All data structures can be reset to their initial state, and, if applicable (for lists, maps, and sets), emptied.

API

Each reducer maker is a higher-order function of a singleoptions object and returns a reducer:

{ ...options}=>(state,action)=>state

For each reducer maker, we describe below how theoptions object is destructured, its default property values, and how some specific properties are used.

Defaults can--and in a lot of casesshould--be overridden.

Each category of actions, e.g.,decrementActionTypes, is an array of action types (i.e., strings), so that several action types can have the same result (cf.Configuring Data Structures, above, where bothPUNCH andKICK decrementlifePoints).

Boolean

{  initialState=false,  trueActionTypes=[],  additionalConditionToTrue=()=>true,  falseActionTypes=[],  additionalConditionToFalse=()=>true,  toggleActionTypes=[],  resetActionTypes=[],}

additionalConditionToTrue andadditionalConditionToFalse are functions ofaction and are used as such:

// ...if(trueActionTypes.includes(action.type)&&additionalConditionToTrue(action)){returntrue;}elseif(falseActionTypes.includes(action.type)&&additionalConditionToFalse(action)){returnfalse;}// ...

The default() => true is equivalent to no additional condition.

Counter

{  initialState=0,  incrementActionTypes=[],  increment=()=>1,  max,  decrementActionTypes=[],  decrement=()=>1,  min,  resetActionTypes=[],}

increment,decrement,max, andmin are functions ofaction. Ifmax isundefined, it is not enforced. Same formin.

List

{  initialState=[],  enqueueActionTypes=[],  dequeueActionTypes=[],  pushActionTypes=[],  popActionTypes=[],  itemGetter=action=>action.payload,  resetActionTypes=[],  emptyActionTypes=[],}

A list can be used as a queue or stack.enqueueActionTypes andpushActionTypes add items to the list, using theitemGetter. The defaultitemGetter adds theFlux Standard Actionpayload to the list.

Map

{  initialState={byId:{},allIds:[],},  addActionTypes=[],  changeActionTypes=[],  removeActionTypes=[],  keyGetter=action=>action.payload.id,  itemGetter=action=>({...action.payload}),  itemModifier=(item,action)=>({...item, ...action.payload}),  resetActionTypes=[],  emptyActionTypes=[],}

map uses thenormalized state shape recommended by Redux, as can be seen from the defaultinitialState. Warning: if you overwriteinitialState, use the same format!

The defaultkeyGetter assumes that the action payload has anid property. The defaultitemModifier overwrites the item's properties (but does not delete the ones that have disappeared in the new action payload).

Set

{  initialState={},  addActionTypes=[],  removeActionTypes=[],  toggleActionTypes=[],  keyGetter=action=>action.payload,  resetActionTypes=[],  emptyActionTypes=[],}

In Redux Data Structures, a set's state is a plain Javascript object with boolean properties, i.e. if and only ifkey is in the set,key is a property ofstate whose value istrue. Example:

{key:true}

When a key is removed from the set, the corresponding property is deleted from the state object:

{}

Value

{  initialState=null,  setActionTypes=[],  valueGetter=action=>action.payload,  resetActionTypes=[],}

value is the simplest data structure (to the extent that calling it a data structure is arguable).

Performance

Redux Data Structures doesn't focus on performance, but on developer productivity. In most cases, performance won't be an issue. If it is, please write an issue or submit a pull request.

Contributing

The code is written in modern Javascript, transpiled with Babel, using Jest for tests. Pull requests are welcome.

License

MIT

Author

Adrien Trouillaud,Codology.net

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp