1.0.0 • Published 7 years ago

eigenstate v1.0.0

Weekly downloads
47
License
MIT
Repository
github
Last release
7 years ago

Eigenstate

Eigenstate

Eigenstate is a complete, modular state management framework for React.js. It provides support for methods.

Methods, like Redux reducers, are predictable and easy to test. The advantage is that they do not require action creators, switch statements, or middleware to provide complete functionality. They are also very simple to write.

Features

  • Tiny, flexible API -- half the size of Redux + React Redux.
  • Support for pure functional / asynchronous methods.
  • Immutable state -- always, automatically.

3 Easy Steps (but seriously)

  1. Create a Store containing state data and methods.

  2. Write your React.js view component, using state data and methods via props.

  3. Connect store and view with the Provider.

/*
A fully working app demonstrating synchronous and asynchronous functionality.
*/
import React from 'react'
import ReactDOM from 'react-dom'
import { Store, Provider } from 'eigenstate'

/*
1
*/
const store = Store({
  count: 0,
  color: 'red',
  increment: (amount, state) => ({ count: state.count + amount }),
  delayedIncrement: (payload, state) => {
    const { amount, delay } = payload
    setTimeout(function callback() { state.increment(amount) }, delay)
  },
  changeColor: (_, state) => ({ color: state.color === 'red' ? 'blue' : 'red' })
})

/*
2
*/
const View = (props) => (
  <div id="counter" style={{backgroundColor: props.color}}>
    { props.count }
    <div onClick={() => props.increment(1)}> INCREMENT </div>
    <div onClick={() => props.delayedIncrement({ amount: 10, delay: 1000 })}>
      SLOW INCREMENT
    </div>
    <div onClick={props.changeColor}> CHANGE COLOR </div>
  </div>
)

/*
3
*/
ReactDOM.render(
  <Provider store={store}>
    <View />
  </Provider>,
  document.getElementById('react-root')  
)

Methods

The example above demonstrates all of these principles.

  1. A method is defined with two parameters, and is called with at most one argument. An argument for the second parameter (state) is provided automatically.

  2. A method may update state by returning updated state data.

  3. A method may invoke other methods. Caveat: if a method calls another method, it's not allowed to return anything. (See here for a deeper explanation)

API

  • Store (function) : Accepts a stateDefinition object and returns an Eigenstate store. The Eigenstate store is a function which returns an immutable state object when invoked.

    • stateDefinition (constructor parameter, object) : an object of key: data | method pairs. Defines the Eigenstate state to be returned by Store. Data can be any JSON, and methods are described here.

    • .subscribe (store property, function) : A function that accepts a function, subscriber. The subscriber is called on every method invocation with an invocationDetails object. To unsubscribe a subscriber, invoke the function returned by <store>.subscribe

    • Provider (React component) : Provides store state to its children. Must be passed a store property to work. Provides state data and methods to its child component via the child component's props.

  • connect (function) : accepts a React component and returns a connect()ed version of that component. The connected version has access to the nearest Provider's state through props. (This comes in handy with React Router.)

  • verboseLogger (function) : an onMethodListener that logs useful information about method invocations to the console. Use by subscribing it to a store, like this:

    const yourStore = Store({ ... }); yourStore.subscribe(verboseLogger)

Relevant concepts

Optimization

Eigenstate state is always immutable. This means that a === comparison will return false if state has changed. This is useful for your React components' shouldComponentUpdate functions. Here is an example shouldComponentUpdate that makes use of immutable state:

//TodoList component
shouldComponentUpdate: function(nextProps) {
  return this.props.todoItems !== nextProps.todoItems //where todoItems is a complex data structure
}

If you implement this across your application, it will never re-render needlessly, making it very fast.

Method purity

Methods may be pure XOR impure. Methods that update state directly by returning data are pure, while methods that invoke other methods are impure.

Async methods go in impure methods. If Eigenstate catches you trying to update state directly from an impure method by returning data, it will throw an error.

This pure vs impure distinction is the central dogma of Eigenstate. Forcing you to separate methods by purity gives you the separate benefits of functional code (for clean application logic) and procedural code (for Ajax calls, and other async things, like animations).

Multiple Stores

You may pass multiple stores to a Provider, provided that the stores are namespaced, like so:

<Provider store={{
  counter: counterStore,
  grid: gridStore
}}>
  <View />
</Provider>

In this example, state from counterStore and gridStore will be accessible from the view via props.counter and props.gridStore respectively.

Effects

Functions returned from methods are called "effects", and are executed after the view component of your application has completely updated. Use sparingly.

Advanced Example

See here.

This is a React Router setup that implements multiple routes in a single page. It demonstrates how to compose stateDefinitions and views through composition. It is a part of a larger boilerplate, which incorporates Webpack and SASS.

1.0.0

7 years ago

0.12.2

8 years ago

0.12.1

8 years ago

0.12.0

8 years ago

0.11.3

8 years ago

0.11.2

8 years ago

0.11.1

8 years ago

0.11.0

8 years ago

0.10.0

8 years ago

0.9.8

8 years ago

0.9.7

8 years ago

0.9.6

8 years ago

0.9.5

8 years ago

0.9.4

8 years ago

0.9.3

8 years ago

0.9.2

8 years ago

0.9.1

8 years ago

0.9.0

8 years ago

0.8.0

8 years ago

0.7.1

8 years ago

0.6.9

8 years ago

0.6.8

8 years ago

0.6.6-rc.0

8 years ago

0.6.5

8 years ago

0.7.0

8 years ago

0.7.0-rc.0

8 years ago

0.6.4

8 years ago

0.6.3

8 years ago

0.6.2

8 years ago

0.5.1

8 years ago

0.4.1

8 years ago

0.4.0

8 years ago

0.3.5

8 years ago

0.3.4

8 years ago

0.3.3

8 years ago

0.3.2

8 years ago

0.3.0

8 years ago

0.2.2

8 years ago

0.2.0

8 years ago

0.1.0

8 years ago

0.0.8

8 years ago

0.0.7

8 years ago

0.0.6

8 years ago

0.0.5

8 years ago

0.0.4

8 years ago

0.0.3

8 years ago

0.0.2

8 years ago