Redux Ensurable
Redux Ensurable helps you to create on demand (async) Redux state and actions...
Sometimes you have actions and states that loads heavy dependencies, like a provider SDK that you don't need loaded on every section of your app.
So, if it's not enough to just have your views/components asynchronous on your app, but your store as well, Redux Ensurable is the right choice for you.
Usage
1. Create your scope module
# ./store/counter.ts
import { action, PossibleAction } from 'redux-ensurable';
export interface CounterState {
value: number;
}
export enum ActionType = {
SET_VALUE = 'counter.SET_VALUE',
INCREMENT_VALUE = 'counter.INCREMENT_VALUE',
DECREMENT_VALUE = 'counter.DECREMENT_VALUE',
};
export const actions = {
setValue(value: number) {
return action({
type: ActionType.SET_VALUE,
payload: value,
});
},
incrementValue(value: number = 1) {
return action({
type: ActionType.INCREMENT_VALUE,
payload: value,
});
},
decrementValue(value: number = 1) {
return action({
type: ActionType.INCREMENT_VALUE,
payload: value,
});
},
};
const defaultState = {
value: 0;
};
export const reducer = (state: CounterState = defaultState, actions: PossibleAction<typeof actions>) => {
switch(action.type) {
case ActionType.SET_VALUE:
return {
...state,
value: action.payload,
};
case ActionType.INCREMENT_VALUE:
return {
...state,
value: state.value + action.payload,
};
case ActionType.DECREMENT_VALUE:
return {
...state,
value: state.value - action.payload,
};
default:
return state;
}
});
2. Create your store
# ./store/index.ts
import {
createEnsurableStore,
} from 'redux-ensurable';
const store = createEnsurableStore({
{
counter: require('./counter'),
counter2: { async: () => import('./counter') },
counter3: { async: () => import('./counter') },
},
});
3. Resolve your state
Ensured state
store.ensure(['counter2', 'counter3'])
.then((ensuredStore) => {
let state = ensuredStore.getState();
console.log('counter2', state.counter2.value);
const {
counter: counterActions,
} = ensuredStore.actions;
ensuredStore.subscribe(state => {
console.log('counter2', state.counter.value);
});
ensuredStore.dispatch(counterActions.incrementValue());
});
Partial state
const state = store.getState();
console.log('counter', state.counter.value);
if (state.counter2 != null) {
console.log('counter2', state.counter2.value);
} else {
store.subscribe(() => {
const state = store.getState();
if (state.counter2 != null) {
console.log('counter2', state.counter2.value);
}
});
store.load(['counter2']);
}
With React
You will need to add React Redux Ensurable to your dependencies
import * as React from 'react';
import { connect } from '@ezsper/react-redux-ensurable';
import { store } from '../store';
export interface MyCounterPropTypes {
value: number;
incrementValue: () => void;
};
class MyCounter extends React.Component<MyCounterPropTypes> {
handleClick = () => {
return this.props.incrementValue();
};
render() {
return <button onClick={this.handleClick}>{this.props.value}</button>;
}
}
export default connect(MyCounterPropTypes)(
store,
['counter2'], // ensure the scopes you want from the store
(state, props) => ({
value: state.counter2.value,
}),
(dispatch, actions) => ({
incrementValue: () => dispatch(actions.counter2.incrementValue()),
}),
);