1.12.3 • Published 6 years ago

redux-elements v1.12.3

Weekly downloads
4
License
MIT
Repository
github
Last release
6 years ago

Redux-elements

Redux-elements is an opinionated framework for holding normalized, log-based state in redux. It comes with the following features:

  • Automatically defined actions to update the data
  • Automatically defined auto-caching selectors based on reselect
  • Can automatically sync with an API module
  • Supports roll-back and "time travel" of actions, efficiently recalculating store state

Redux-elements uses immutable.js, reselect and redux-saga. It is compatible with react-redux.

Docs

Check out the documentation pages.

Installation

You can install this repository via npm.

npm i redux-elements

Automatically defined actions

No need to endlessly redefine simple CRUD actions.

Redux-elements supports the following actions out of the box:

  • add: Adds one or more items to the data
  • set: Wipes existing data and replaces it with one or more elements
  • clear: Wipes existing data, resets this element to initial (empty) state
  • update: Updates one or more rows in the data
  • upsert: Update or create one or more rows in the data
  • patch: Update select columns of one or more rows in the data
  • delete: Delete one or more rows in the data

Example:

const Session = new StateElement("session","");
const User = new StateElement("user","");
const store = createStore(combineReducers({
  sessions: Session.reducer,
  users: User.reducer
}));
store.dispatch(
  Session.changeState.set([
    {
      id: "sid1",
      userId: "uid1"
    },
    {
      id: "sid2",
      userId: "uid1"
    }
  ])
);
store.dispatch(
  Session.changeState.upsert([
    {
      id: "sid3",
      userId: "uid3"
    },
    {
      id: "sid2",
      userId: "newUserId"
    }
  ])
)
store.getState()
/* {
  sessions: [
    {
      id: "sid1",
      userId: "uid1"
    },
    {
      id: "sid2",
      userId: "newUserId"
    },
    {
      id: "sid3",
      userId: "uid3"
    }
  ],
  users: []
  }
 *

Auto-caching selectors

Redux-elements automatically exposes chainable, optimally caching selectors, supporting database-style joins.

Example:

User.select("duplicateNames")
  .fromState(state)
  .keyBy("firstName") // autocaching
  .filter(listOfUsers => listOfUsers.length>=2, 2) // caching by parameter `2`
  .map(listOfUsers => listOfUsers.first(), "first")  // caching by parameter `"first"`

User.select("duplicateNames")
  .fromState(state)
  .keyBy("firstName") // uses cached result
  .filter(listOfUsers => listOfUsers.length>=2, 2) // uses cached result
  .map(listOfUsers => listOfUsers.last(), "last")  // calculated since caching parameters not equal

See documentation for more details.

Roll-back and time-travel of actions

Redux-elements is built for eager execution of actions in the frontend and subsequent sync with a stream-processing backend, e.g. Apache Kafka.

This means that Redux-Elements needs to support roll-back and reordering of actions. An example is the following chain of events:

  • A frontend using Redux-elements dispatches and eagerly executes action a1, changing a part of the store. The frontend sends a1 via API to the backend.
  • Another frontend or part of the backend dispatches action a0, which arrives at the backend before action a1.
  • Action a0 is processed by the backend - the state in the backend is therefore defined by the actions sequence [a0]. Action a0 is sent to all frontends.
  • Action a1 arrives in the backend and is processed there - the "true" state is defined by the action sequence [a0, a1]. Action a1 (and its order in the action sequence) is sent back to all frontends.
  • Action a0 arrives in the frontend using Redux-elements. It needs to be inserted before all actions which are currently "local only" - i.e. don't have a response from backend yet. You can use the Redux-elements TimeMachine object for this, wrapping the action with TimeMachine.makeActionInsertBefore(a0, "id of a1"). Redux-elements efficiently recalculates the state from a0, leaving all previous (still valid) actions untouched.
  • Action a1 arrives back in the frontend using Redux-elements. Since it's already processed at the right position in the action sequence, nothing needs to be done except noting its "true" position in the backend sequence of actions.
import { createStore } from "redux";
import { TimeMachine } from "redux-elements";

// ...

const tm = new TimeMachine({
  users: userReducer,
  projects: projectReducer
})

const store = createStore(tm.reducer)

// ...

const action = tm.createRollbackAction("actionId5");
store.dispatch(action) // rolls back action with id "actionId5"

// ...

const actionNormal = {
  type: "ADD_USER",
  payload: { ... },
  actionId: "something"
}
const actionTimeTraveller = tm.makeActionInsertBefore(actionNormal, "actionId6");
store.dispatch(actionTimeTraveller) // action is executed before action with id "actionId6"

License

Redux-elements is published under MIT license.

1.12.3

6 years ago

1.12.2

6 years ago

1.12.1

6 years ago

1.12.0

6 years ago

1.11.9

6 years ago

1.11.8

6 years ago

1.11.7

6 years ago

1.11.6

6 years ago

1.11.5

6 years ago

1.11.4

6 years ago

1.11.3

6 years ago

1.11.2

6 years ago

1.11.1

6 years ago

1.11.0

6 years ago

1.9.0

6 years ago

1.8.0

6 years ago

1.7.0

6 years ago

1.6.0

6 years ago

1.5.1

6 years ago

1.5.0

6 years ago

1.4.0

6 years ago

1.3.0

6 years ago

1.2.0

6 years ago

1.1.0

6 years ago