109 lines
2.2 KiB
JavaScript
109 lines
2.2 KiB
JavaScript
import history from 'history/browser';
|
|
import UrlPattern from 'url-pattern';
|
|
|
|
export const LOCATION_CHANGED = 'ROUTER_LOCATION_CHANGED';
|
|
export const PUSH = 'ROUTER_PUSH';
|
|
export const REPLACE = 'ROUTER_REPLACE';
|
|
|
|
export function locationChanged(route, params, location) {
|
|
return {
|
|
type: LOCATION_CHANGED,
|
|
route,
|
|
params,
|
|
location
|
|
};
|
|
}
|
|
|
|
export function push(path) {
|
|
return {
|
|
type: PUSH,
|
|
path
|
|
};
|
|
}
|
|
|
|
export function replace(path) {
|
|
return {
|
|
type: REPLACE,
|
|
path
|
|
};
|
|
}
|
|
|
|
export function routeReducer(state = {}, action) {
|
|
if (action.type === LOCATION_CHANGED) {
|
|
return {
|
|
route: action.route,
|
|
params: action.params,
|
|
location: action.location
|
|
};
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
export function routeMiddleware() {
|
|
return next => action => {
|
|
switch (action.type) {
|
|
case PUSH:
|
|
history.push(action.path);
|
|
break;
|
|
case REPLACE:
|
|
history.replace(action.path);
|
|
break;
|
|
default:
|
|
return next(action);
|
|
}
|
|
};
|
|
}
|
|
|
|
function decode(location) {
|
|
location.pathname = decodeURIComponent(location.pathname);
|
|
return location;
|
|
}
|
|
|
|
function match(routes, location) {
|
|
let params;
|
|
for (let i = 0; i < routes.length; i++) {
|
|
params = routes[i].pattern.match(location.pathname);
|
|
if (params !== null) {
|
|
const keys = Object.keys(params);
|
|
for (let j = 0; j < keys.length; j++) {
|
|
params[keys[j]] = decodeURIComponent(params[keys[j]]);
|
|
}
|
|
return locationChanged(routes[i].name, params, decode(location));
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export default function initRouter(routes, store) {
|
|
const patterns = [];
|
|
const opts = {
|
|
segmentValueCharset: 'a-zA-Z0-9-_.%'
|
|
};
|
|
|
|
Object.keys(routes).forEach(name =>
|
|
patterns.push({
|
|
name,
|
|
pattern: new UrlPattern(routes[name], opts)
|
|
})
|
|
);
|
|
|
|
let matched = match(patterns, history.location);
|
|
if (matched) {
|
|
store.dispatch(matched);
|
|
} else {
|
|
matched = { location: {} };
|
|
}
|
|
|
|
history.listen(({ location }) => {
|
|
const nextMatch = match(patterns, location);
|
|
if (
|
|
nextMatch &&
|
|
nextMatch.location.pathname !== matched.location.pathname
|
|
) {
|
|
matched = nextMatch;
|
|
store.dispatch(matched);
|
|
}
|
|
});
|
|
}
|