Get router history working with flux

This commit is contained in:
Berkeley Martinez
2015-12-31 17:39:29 -08:00
parent bfaed15c5f
commit 1c6e761299
5 changed files with 117 additions and 53 deletions

View File

@ -9,6 +9,7 @@ import { hydrate } from 'thundercats';
import { render$ } from 'thundercats-react';
import { app$ } from '../common/app';
import synchroniseHistory from './synchronise-history';
const debug = debugFactory('fcc:client');
const DOMContianer = document.getElementById('fcc');
@ -23,18 +24,6 @@ const appLocation = createLocation(
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
app$({ history, location: appLocation })
.flatMap(
@ -49,40 +38,22 @@ app$({ history, location: appLocation })
({ nextLocation, props }, appCat) => ({ nextLocation, props, appCat })
)
.doOnNext(({ appCat }) => {
const appActions = appCat.getActions('appActions');
const appStore = appCat.getStore('appStore');
const { updateLocation, goTo, goBack } = appCat.getActions('appActions');
const appStore$ = appCat.getStore('appStore');
const route$ = location$(history)
.pluck('pathname')
.distinctUntilChanged();
const routerState$ = appStore$
.map(({ location }) => location)
.distinctUntilChanged(
location => location && location.key ? location.key : location
);
appStore
.pluck('route')
.filter(route => !!route)
.withLatestFrom(
route$,
(nextRoute, currentRoute) => ({ currentRoute, nextRoute })
)
// 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));
synchroniseHistory(
history,
updateLocation,
goTo,
goBack,
routerState$
);
})
.flatMap(({ props, appCat }) => {
props.history = history;

View 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(() => {});
}

View File

@ -38,8 +38,14 @@ export default Actions({
});
},
updateRoute(route) {
return { route };
},
goBack: null
// routing
goTo: null,
goBack: null,
updateLocation(location) {
return {
transform(state) {
return { ...state, location };
}
};
}
});

View File

@ -20,7 +20,12 @@ export default Store({
value: initValue
},
init({ instance: appStore, args: [cat] }) {
const { updateRoute, getUser, setTitle } = cat.getActions('appActions');
const {
updateLocation,
getUser,
setTitle
} = cat.getActions('appActions');
const register = createRegistrar(appStore);
const {
toggleQuestions,
@ -33,7 +38,17 @@ export default Store({
} = cat.getActions('hikesActions');
// app
register(setter(fromMany(getUser, setTitle, updateRoute)));
register(
fromMany(
setter(
fromMany(
getUser,
setTitle
)
),
updateLocation
)
);
// hikes
register(

View File

@ -218,9 +218,12 @@ export default Actions({
const currentHike = findNextHike(hikes, id);
// go to next route
state.route = currentHike && currentHike.dashedName ?
`/hikes/${ currentHike.dashedName }` :
'/hikes';
state.location = {
action: 'PUSH',
pathname: currentHike && currentHike.dashedName ?
`/hikes/${ currentHike.dashedName }` :
'/hikes'
};
const hikesApp = {
...state.hikesApp,