Skip to content

Instantly share code, notes, and snippets.

@kamilglod
Last active January 19, 2017 21:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kamilglod/972bf23c0bb9d5a33a0802f359b78e11 to your computer and use it in GitHub Desktop.
Save kamilglod/972bf23c0bb9d5a33a0802f359b78e11 to your computer and use it in GitHub Desktop.
Aurelia redux sync, updates aurelia's viewModel each time the change of state occured. Aurelia, Redux, ImmutableJS
import { getHttp } from 'utils/fetch';
import { HISTORY_URL } from 'conf/urls';
const types = {
START_FETCHING_HISTORY: 'START_FETCHING_HISTORY',
FINISH_FETCHING_HISTORY: 'FINISH_FETCHING_HISTORY',
INVALIDATE_HISTORY: 'INVALIDATE_HISTORY',
};
function _startFetchingHistory() {
return {
type: types.START_FETCHING_HISTORY,
};
}
function _finishFetchingHistory(data) {
return {
type: types.FINISH_FETCHING_HISTORY,
data,
};
}
function fetchHistory(dispatch) {
dispatch(_startFetchingHistory());
return getHttp().fetch(HISTORY_URL)
.then(response => response.json())
.then(json => dispatch(_finishFetchingHistory(json)));
}
function _isFetchNeeded(historyState) {
if (historyState.get('isFetching')) {
return false;
} else if (historyState.get('didInvalidate')) {
return true;
} else {
return !historyState.get('fetched');
}
}
function fetchHistoryIfNeeded() {
return (dispatch, getState) => {
const historyState = getState().history;
if (!_isFetchNeeded(historyState)) {
return Promise.resolve();
}
return fetchHistory(dispatch);
};
}
function invalidateHistory() {
return {
type: types.INVALIDATE_HISTORY,
}
}
export { types, fetchHistoryIfNeeded, fetchHistory, invalidateHistory, };
<template>
${history.data}
</template>
import StoreSync from 'utils/store-sync';
import { fetchHistoryIfNeeded } from 'flux/actions/history';
export class History {
constructor() {
this.store = StoreSync.init(this, 'history', 'auth').store;
this.store.dispatch(fetchHistoryIfNeeded());
// you can now access states properties
console.log(this.history, this.auth);
}
}
import { List, Map } from 'immutable';
import { types } from '../actions/history';
import { types as authTypes } from '../actions/auth';
function getInitialState() {
return new Map({
isFetching: false,
didInvalidate: false,
fetched: false,
data: new List(),
});
}
export default function(state, action) {
if (!state) {
state = getInitialState();
}
switch (action.type) {
case types.START_FETCHING_HISTORY:
state = state.set('isFetching', true);
break;
case types.FINISH_FETCHING_HISTORY:
state = getInitialState().set('data', action.data).set('fetched', true);
break;
case types.INVALIDATE_HISTORY:
state = state.set('didInvalidate', true);
break;
case authTypes.LOGGED_OUT:
state = getInitialState();
break;
}
return state;
}
import { Container } from 'aurelia-dependency-injection';
import store from 'flux/store';
export default class StoreSync {
static init(...args) {
return new StoreSync(...args);
}
constructor(viewModel, ...args) {
this.viewModel = viewModel;
this.store = Container.instance.get(store);
this._syncStateKeys = args;
this._initSyncedStates();
this._sync(true);
this._syncInvoker = this.store.subscribe(() => this._sync());
}
detached() {
if (this._syncInvoker) {
this._syncInvoker();
}
}
_fillSyncedState(state) {
for (const stateKey of this._syncStateKeys) {
this._syncedState[stateKey] = state[stateKey];
}
}
_initSyncedStates() {
const state = this.store.getState();
this._syncedState = {};
this._fillSyncedState(state);
}
_isSyncNeeded() {
const state = this.store.getState();
for (const stateKey of this._syncStateKeys) {
if (this._syncedState[stateKey] != state[stateKey]) {
return true;
}
}
return false;
}
_sync(force = false) {
const state = this.store.getState();
if (!force && !this._isSyncNeeded()) {
return;
}
for (const stateKey of this._syncStateKeys) {
this.viewModel[stateKey] = state[stateKey].toJS();
}
this._fillSyncedState(state);
}
}
import { createStore, applyMiddleware, compose, combineReducers } from 'redux'
import thunkMiddleware from 'redux-thunk'
import auth from './reducers/auth';
import history from './reducers/history';
const reducers = combineReducers({
auth,
history,
});
function configureStore() {
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
return createStore(
reducers,
composeEnhancers(
applyMiddleware(
thunkMiddleware,
),
)
)
}
export default configureStore();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment