99 lines
2.0 KiB
JavaScript
99 lines
2.0 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) {
|
|
Object.keys(params).forEach(key => {
|
|
params[key] = decodeURIComponent(params[key]);
|
|
});
|
|
|
|
const query = {};
|
|
new URLSearchParams(location.search).forEach((value, key) => {
|
|
query[key] = value;
|
|
});
|
|
|
|
return {
|
|
type: LOCATION_CHANGED,
|
|
route,
|
|
params,
|
|
query,
|
|
path: decodeURIComponent(location.pathname)
|
|
};
|
|
}
|
|
|
|
export function push(path) {
|
|
return {
|
|
type: PUSH,
|
|
path
|
|
};
|
|
}
|
|
|
|
export function replace(path) {
|
|
return {
|
|
type: REPLACE,
|
|
path
|
|
};
|
|
}
|
|
|
|
export function routeReducer(state = {}, { type, ...action }) {
|
|
if (type === LOCATION_CHANGED) {
|
|
return action;
|
|
}
|
|
|
|
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 match(routes, location) {
|
|
for (let i = 0; i < routes.length; i++) {
|
|
const params = routes[i].pattern.match(location.pathname);
|
|
if (params !== null) {
|
|
return locationChanged(routes[i].name, params, location);
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
history.listen(({ location }) => {
|
|
const nextMatch = match(patterns, location);
|
|
if (nextMatch && nextMatch.path !== matched?.path) {
|
|
matched = nextMatch;
|
|
store.dispatch(matched);
|
|
}
|
|
});
|
|
}
|