Package Exports
- resolve-redux
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (resolve-redux) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
resolve-redux
This package serves as a helper for creating the Redux storage.
Basic Usage
How to create a Redux store
import { createStore, applyMiddleware } from 'redux';
import axios from 'axios';
import {
createReducer,
sendCommandMiddleware
} from 'resolve-redux';
const aggregate = {
name: 'User',
commands: {
createUser: (state, { aggregateId, payload }) => ({
type: 'UserCreated',
aggregateId,
payload
}),
removeUser: (state, { aggregateId }) => ({
type: 'UserRemoved',
aggregateId
})
}
};
const readModel = {
name: 'Users',
initialState: [],
eventHandlers: {
UserCreated(state, event) {
return state.concat({
...event.payload,
id: event.aggregateId
});
},
UserRemoved(state, event) {
return state.filter(item =>
item.id !== event.aggregateId
);
}
}
};
const reducer = createReducer(readModel);
const store = createStore(
reducer,
readModel.initialState,
applyMiddleware(
sendCommandMiddleware({
sendCommand: command => axios.post('/api/commands', command)
})
)
);
How to generate action from aggregate
import { createActions } from 'resolve-redux';
import { connect, bindActionCreators } from 'redux';
import App from './components/App';
export const aggregate {
name: 'User',
commands: {
createUser: (state, { aggregateId, payload }) => ({
type: 'UserCreated',
aggregateId,
payload
})
}
};
export const customActions = {
deleteAll: () => ({
type: 'DELETE_ALL'
})
}
function mapDispatchToProps(dispatch) {
actions: bindActionCreators(createActions(aggregate, customActions))
}
export default connect(() => {}, mapDispatchToProps)(App);
How to send commands to the server
import { actions } from 'resolve-redux';
export function sendCommandAddTodoItem(aggregateId) {
return {
type: 'SEND_COMMAND_ADD_TODO_ITEM',
aggregateId,
aggregateName: 'TodoList',
payload: { name: 'todo-list' },
command: {
type: 'TodoListItemAdd',
},
};
}
store.dispatch(sendCommandAddTodoItem('aggregateId'));
// or
store.dispatch(actions.sendCommand({
aggregateId: 'aggregateId',
aggregateName: 'TodoList',
payload: { name: 'todo-list' },
command: {
type: 'TodoListItemRemove',
},
}));
Advanced Usage
Support for Optimistic Updates
const readModel = {
name: 'TodoList',
initialState: [],
eventHandlers: {
TodoListItemUpdateText(state, event) {
return state.concat({
...event.payload,
id: event.aggregateId
});
}
}
};
const reducer = createReducer(readModel, (state, action) => {
switch (action.type) {
case 'SEND_COMMAND_TODO_UPDATE_TEXT': {
// Optimistic update
if(!action.error) {
return state.map(item => {
if(item.id === event.aggregateId) {
return {
...item,
text: action.payload.text,
textBeforeOptimisticUpdate: item.text
};
}
});
} else {
// Revert optimistic update
return state.map(item => {
if(item.id === event.aggregateId) {
return {
...item,
text: item.textBeforeOptimisticUpdate
};
}
});
}
}
default:
return state;
}
});