import { Component, ValidationMap } from 'react';
import { History } from 'history';
import { Store, RouterStoreState } from './Store';
import * as PropTypes from 'prop-types';
import { Match, ValOrFunc, ToProps, NavParams, createNavParams } from './utils';
export type NavProviderPropsTyped
= {
to: ToProps;
match?: ValOrFunc;
replace?: boolean;
// render
renderChild: (params: NavParams) => JSX.Element;
noSubscribe?: boolean;
};
export type NavProviderProps = NavProviderPropsTyped;
export type NavProviderContext = {
routerStore: Store;
router: { history: History };
};
export class NavProvider extends Component {
static displayName: string = 'NavProvider';
static contextTypes: ValidationMap = {
routerStore: PropTypes.instanceOf(Store), // from RouterProvider or parent Route
router: PropTypes.any,
};
context: NavProviderContext;
private unsubscribe: () => void;
private isUnmounted: boolean = false;
constructor(props: NavProviderProps, context: NavProviderContext) {
super(props, context);
if (!context.routerStore || !context.routerStore.getState() || !context.router || !context.router.history) {
throw new Error('InjectMatch need a RouterProvider as ancestor');
}
}
componentDidMount() {
if (this.props.noSubscribe !== true) {
this.unsubscribe = this.context.routerStore.subscribe(() => {
this.update();
});
}
}
UNSAFE_componentWillReceiveProps(nextProps: NavProviderProps): void {
if (this.props.noSubscribe !== nextProps.noSubscribe) {
if (nextProps.noSubscribe && this.unsubscribe) {
this.unsubscribe();
} else {
this.unsubscribe = this.context.routerStore.subscribe(() => {
this.update();
});
}
}
}
componentWillUnmount(): void {
this.isUnmounted = true;
if (this.unsubscribe) {
this.unsubscribe();
}
}
render(): JSX.Element {
const { renderChild, to, replace, match } = this.props;
const parentRouterState: RouterStoreState = this.context.routerStore.getState();
const childParams: NavParams = createNavParams(
to,
this.context.router.history,
parentRouterState.location,
replace,
match,
parentRouterState.match,
);
return renderChild(childParams);
}
private update(): void {
if (this.isUnmounted === false) {
this.forceUpdate();
}
}
}