Skip to content

Instantly share code, notes, and snippets.

@dpr-dev
Created May 13, 2019 15:08
Show Gist options
  • Save dpr-dev/0bb7d91dd8b834d0843c24429d953ac6 to your computer and use it in GitHub Desktop.
Save dpr-dev/0bb7d91dd8b834d0843c24429d953ac6 to your computer and use it in GitHub Desktop.
import * as React from 'react';
import { push, replace } from './router';
export type RouteValidationResult = {
url: string,
needRedirect: boolean,
state?: any,
replace?: boolean
};
export type Options = {
fn: (url: string) => Promise<RouteValidationResult>,
onValidationRequest?: Function,
onValidationFailure?: Function,
placeholder?: () => React.ReactNode,
errorPlaceholder?: () => React.ReactNode,
skipeValidatonOnUpdate: boolean
};
type ValidationState = 'request' | 'complated' | 'failed';
export const addValidator =
(Component: React.ComponentType, options: Options) => {
type Props = { url: string };
type State = { validationState: ValidationState };
return class extends React.Component<Props, State> {
constructor(props: any) {
super(props);
this.state = { validationState: 'request' };
}
public componentDidMount = () => {
this._validateRequest(false);
}
public componentDidUpdate = (props) => {
if (options.skipeValidatonOnUpdate) {
return;
}
if (this.props.url !== props.url) {
this._validateRequest(true);
}
}
public render = () => {
const { validationState: state } = this.state;
const { placeholder, errorPlaceholder } = options;
if (state === 'request') {
return !!placeholder ? placeholder() : null;
}
if (state === 'complated') {
return <Component {...this.props} />;
}
return !!errorPlaceholder ? errorPlaceholder() : null;
}
private _validateRequest = async (force: boolean) => {
const isNormalized =
this.props.url.includes('normalized');
if (!isNormalized || force) {
this.setState({ validationState: 'request' });
const {
onValidationRequest,
onValidationFailure
} = options;
try {
if (!!onValidationRequest) {
await onValidationRequest();
}
await this._executeValidation();
} catch (e) {
if (!!onValidationFailure) {
await onValidationFailure(e);
}
return this.setState({ validationState: 'failed' });
}
}
this.setState({ validationState: 'complated' });
}
private _executeValidation = async () => {
const {
needRedirect,
replace: r,
url,
state
} = await options.fn(this.props.url);
if (needRedirect) {
const action = r ? replace : push;
const u =
url.includes('?')
? `${url}&normalized=true`
: `${url}?normalized=true`;
action(u, state);
}
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment