Get router history working with flux
This commit is contained in:
@ -9,6 +9,7 @@ import { hydrate } from 'thundercats';
|
|||||||
import { render$ } from 'thundercats-react';
|
import { render$ } from 'thundercats-react';
|
||||||
|
|
||||||
import { app$ } from '../common/app';
|
import { app$ } from '../common/app';
|
||||||
|
import synchroniseHistory from './synchronise-history';
|
||||||
|
|
||||||
const debug = debugFactory('fcc:client');
|
const debug = debugFactory('fcc:client');
|
||||||
const DOMContianer = document.getElementById('fcc');
|
const DOMContianer = document.getElementById('fcc');
|
||||||
@ -23,18 +24,6 @@ const appLocation = createLocation(
|
|||||||
location.pathname + location.search
|
location.pathname + location.search
|
||||||
);
|
);
|
||||||
|
|
||||||
function location$(history) {
|
|
||||||
return Rx.Observable.create(function(observer) {
|
|
||||||
const dispose = history.listen(function(location) {
|
|
||||||
observer.onNext(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
return Rx.Disposable.create(() => {
|
|
||||||
dispose();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns an observable
|
// returns an observable
|
||||||
app$({ history, location: appLocation })
|
app$({ history, location: appLocation })
|
||||||
.flatMap(
|
.flatMap(
|
||||||
@ -49,40 +38,22 @@ app$({ history, location: appLocation })
|
|||||||
({ nextLocation, props }, appCat) => ({ nextLocation, props, appCat })
|
({ nextLocation, props }, appCat) => ({ nextLocation, props, appCat })
|
||||||
)
|
)
|
||||||
.doOnNext(({ appCat }) => {
|
.doOnNext(({ appCat }) => {
|
||||||
const appActions = appCat.getActions('appActions');
|
const { updateLocation, goTo, goBack } = appCat.getActions('appActions');
|
||||||
const appStore = appCat.getStore('appStore');
|
const appStore$ = appCat.getStore('appStore');
|
||||||
|
|
||||||
const route$ = location$(history)
|
const routerState$ = appStore$
|
||||||
.pluck('pathname')
|
.map(({ location }) => location)
|
||||||
.distinctUntilChanged();
|
.distinctUntilChanged(
|
||||||
|
location => location && location.key ? location.key : location
|
||||||
|
);
|
||||||
|
|
||||||
appStore
|
synchroniseHistory(
|
||||||
.pluck('route')
|
history,
|
||||||
.filter(route => !!route)
|
updateLocation,
|
||||||
.withLatestFrom(
|
goTo,
|
||||||
route$,
|
goBack,
|
||||||
(nextRoute, currentRoute) => ({ currentRoute, nextRoute })
|
routerState$
|
||||||
)
|
);
|
||||||
// only continue when route change requested
|
|
||||||
.filter(({ currentRoute, nextRoute }) => currentRoute !== nextRoute)
|
|
||||||
.doOnNext(({ nextRoute }) => {
|
|
||||||
debug('route change', nextRoute);
|
|
||||||
history.pushState(history.state, nextRoute);
|
|
||||||
})
|
|
||||||
.subscribeOnError(err => console.error(err));
|
|
||||||
|
|
||||||
appActions.goBack.subscribe(function() {
|
|
||||||
history.goBack();
|
|
||||||
});
|
|
||||||
|
|
||||||
appActions
|
|
||||||
.updateRoute
|
|
||||||
.pluck('route')
|
|
||||||
.doOnNext(route => {
|
|
||||||
debug('update route', route);
|
|
||||||
history.pushState(history.state, route);
|
|
||||||
})
|
|
||||||
.subscribeOnError(err => console.error(err));
|
|
||||||
})
|
})
|
||||||
.flatMap(({ props, appCat }) => {
|
.flatMap(({ props, appCat }) => {
|
||||||
props.history = history;
|
props.history = history;
|
||||||
|
69
client/synchronise-history.js
Normal file
69
client/synchronise-history.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import { Disposable, Observable } from 'rx';
|
||||||
|
|
||||||
|
export function location$(history) {
|
||||||
|
return Observable.create(function(observer) {
|
||||||
|
const dispose = history.listen(function(location) {
|
||||||
|
observer.onNext(location);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Disposable.create(() => {
|
||||||
|
dispose();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const emptyLocation = {
|
||||||
|
pathname: '',
|
||||||
|
search: '',
|
||||||
|
hash: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
let prevKey;
|
||||||
|
let isSyncing = false;
|
||||||
|
export default function synchroniseHistory(
|
||||||
|
history,
|
||||||
|
updateLocation,
|
||||||
|
goTo,
|
||||||
|
goBack,
|
||||||
|
routerState$
|
||||||
|
) {
|
||||||
|
routerState$.subscribe(
|
||||||
|
location => {
|
||||||
|
|
||||||
|
if (!location) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// store location has changed, update history
|
||||||
|
if (location.key !== prevKey) {
|
||||||
|
isSyncing = true;
|
||||||
|
history.transitionTo({ ...emptyLocation, ...location });
|
||||||
|
isSyncing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
location$(history)
|
||||||
|
.doOnNext(location => {
|
||||||
|
prevKey = location.key;
|
||||||
|
|
||||||
|
if (isSyncing) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return updateLocation(location);
|
||||||
|
})
|
||||||
|
.subscribe(() => {});
|
||||||
|
|
||||||
|
goTo
|
||||||
|
.doOnNext((route = '/') => {
|
||||||
|
history.push(route);
|
||||||
|
})
|
||||||
|
.subscribe(() => {});
|
||||||
|
|
||||||
|
goBack
|
||||||
|
.doOnNext(() => {
|
||||||
|
history.goBack();
|
||||||
|
})
|
||||||
|
.subscribe(() => {});
|
||||||
|
}
|
@ -38,8 +38,14 @@ export default Actions({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
updateRoute(route) {
|
// routing
|
||||||
return { route };
|
goTo: null,
|
||||||
},
|
goBack: null,
|
||||||
goBack: null
|
updateLocation(location) {
|
||||||
|
return {
|
||||||
|
transform(state) {
|
||||||
|
return { ...state, location };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
@ -20,7 +20,12 @@ export default Store({
|
|||||||
value: initValue
|
value: initValue
|
||||||
},
|
},
|
||||||
init({ instance: appStore, args: [cat] }) {
|
init({ instance: appStore, args: [cat] }) {
|
||||||
const { updateRoute, getUser, setTitle } = cat.getActions('appActions');
|
const {
|
||||||
|
updateLocation,
|
||||||
|
getUser,
|
||||||
|
setTitle
|
||||||
|
} = cat.getActions('appActions');
|
||||||
|
|
||||||
const register = createRegistrar(appStore);
|
const register = createRegistrar(appStore);
|
||||||
const {
|
const {
|
||||||
toggleQuestions,
|
toggleQuestions,
|
||||||
@ -33,7 +38,17 @@ export default Store({
|
|||||||
} = cat.getActions('hikesActions');
|
} = cat.getActions('hikesActions');
|
||||||
|
|
||||||
// app
|
// app
|
||||||
register(setter(fromMany(getUser, setTitle, updateRoute)));
|
register(
|
||||||
|
fromMany(
|
||||||
|
setter(
|
||||||
|
fromMany(
|
||||||
|
getUser,
|
||||||
|
setTitle
|
||||||
|
)
|
||||||
|
),
|
||||||
|
updateLocation
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
// hikes
|
// hikes
|
||||||
register(
|
register(
|
||||||
|
@ -218,9 +218,12 @@ export default Actions({
|
|||||||
const currentHike = findNextHike(hikes, id);
|
const currentHike = findNextHike(hikes, id);
|
||||||
|
|
||||||
// go to next route
|
// go to next route
|
||||||
state.route = currentHike && currentHike.dashedName ?
|
state.location = {
|
||||||
|
action: 'PUSH',
|
||||||
|
pathname: currentHike && currentHike.dashedName ?
|
||||||
`/hikes/${ currentHike.dashedName }` :
|
`/hikes/${ currentHike.dashedName }` :
|
||||||
'/hikes';
|
'/hikes'
|
||||||
|
};
|
||||||
|
|
||||||
const hikesApp = {
|
const hikesApp = {
|
||||||
...state.hikesApp,
|
...state.hikesApp,
|
||||||
|
Reference in New Issue
Block a user