redax
v0.0.0
Published
A simple flux architecture that combines actions & reducers and maps your store's state directly to your components
Downloads
13
Maintainers
Readme
Redax
Redax combines your actions & reducers to reduce the amount of files you'll need open, and amount of code you have to write - no more searching through dozens of files to find the reducer that matches your action, and no more constants for action types.
Redax also lets you access the entire state tree from every action so that you can easily store it in local storage, reset the entire state, or update multiple collections of data easily.
The redax Store has a very useful map
function to connect your store directly to a component's props. No more need to manually add and remove listeners for state changes, or wrap your application with a provider. Because redax uses immutablejs it internally difs your previous and next state, so that components will only update if a change has been made.
By default redax will allow you to chain actions and handle asynchronous requests as calls made to actions from inside an action are deferred until the action has been resolved.
Usage
Create a store
A store's default state is an immutablejs Map
. We call our setCount
action after creation to set the initial count value, but this could set the entire initial state of your application, or be used to reset the state if you need to do so (which you should do with state.clear()
).
// store.js
import { Store } from 'redax';
import * as actions from './actions';
const store = new Store(
// Object containing our actions
actions
);
store.actions.setCount();
export default store;
Actions
Every action is also a reducer, so they must all return the state. The state in each action is the entire state of the store. It's recommended that you use setIn
and deleteIn
for grouping related data (example a little further down).
// actions.js
// Used to set the initial count value
export function setCount (state) {
return state.set('count', 0);
}
Combine multiple action files
Use Object.assign
or similar, e.g. _.extend
, to combine multiple sets of actions.
// store.js
import * as login from './login';
import * as todo from './todo';
const store = new Store(
Object.assign(
{},
login,
todo
)
);
Chaining actions
Notice that the incrementThenDecrementTwice
action calls the decrement
action twice. The decrement
calls will be deferred until incrementThenDecrementTwice
is resolved, this means that you can easily chain actions, and handle asynchronous requests.
// actions.js
export function decrement (state) {
return state.set('count', state.get('count') - 1);
}
export function incrementThenDecrementTwice (state) {
this.actions.decrement();
this.actions.decrement();
return state.set('count', state.get('count') + 1);
}
Asynchronous example
Here we make an asynchronous request and then call either our success or failure action. You can access the store's actions via this.actions
if you do not have access to the store itself. Notice how we group our state into login
and auth
because we have access to the entire state.
// login.js
export function loginSuccess(state, response) {
const login = state.get('login', Map())
.delete('loading')
.delete('error');
return state.set('login', login)
.setIn(['auth', 'token'], response);
}
export function loginFailure(state, error) {
const login = state.get('login', Map())
.delete('loading')
.set('error', error);
return state.set('login', login)
.deleteIn(['auth', 'token']);
}
export function login(state, username, password) {
const login = state.get('login', Map())
.set('loading', true)
.delete('error');
request('/login/')
.data({username, password})
.send()
.then(this.actions.loginSuccess, this.actions.loginFailure);
return state.set('login', login)
.deleteIn(['auth', 'token']);
}
Connecting your store state to your components
Connect your store's state to your components easily with store.map
. Notice that we do not need to connect our actions to our component as these are automatically dispatched on call.
// component.js
import store from './store';
// Destructuring our actions from the store
const { actions: { incrementThenDecrementTwice } } = store;
class Component extends React.Component {
render() {
const { count } = this.props;
return (
<button onClick={incrementThenDecrementTwice}>
Count: {count}
</button>
);
}
}
function stateToProps(state) {
return {
count: state.get('count')
};
}
export default store.map(stateToProps).to(Component);