UNPKG

preact-batteries

Version:

Batteries for you projects with Preact, TypeScript (or Babel)

92 lines (78 loc) 2.68 kB
import { CompatibleComponentInterface, ComponentModule } from "./module-system"; class RenderMethodNotDefinedError extends Error { constructor() { super( "[preact-batteries.trouble-free-component]: render method in your component is not defined" ); } } /** * This function allows you to easily wrap your method with * try catch which will trigger your onError listener, which will * be called then within a context of class. Useful when you want intercept * errors among several (or all) methods of your class */ export function listenComponentMethodForErrors( context, methodName: string, onError?: (e: Error) => void ) { const old: Function | undefined = context[methodName]; if (methodName === "render" && !old) { throw new RenderMethodNotDefinedError(); } context[methodName] = function(...args) { try { if (methodName === "render") { return old.call(context, ...args); } old && old.call(context, ...args); } catch (e) { if (onError) { onError.call(context, e); } } }.bind(context); } const ERROR_MESSAGE = "[CRITICAL ERROR]"; function renderFunction() { return ERROR_MESSAGE; } function onErrorFunc(e: Error | string) { this.render = renderFunction; console.error( `[preact-batteries.troube-free-component]: you had error in one of your methods in component. You can distinguish one with error by looking at your interface. It should show ${ERROR_MESSAGE}. Also, here is error message. Logging error after this message.` ); if (e instanceof Error) { console.error(e.stack); } else { console.error(e); } } function onAppearedErrorFunc(e: Error) { if (this.forceUpdate) { onErrorFunc.call(this, e); this.setState({ __error_state_7: Math.random() * 1000 }); } else { console.warn( `[preact-batteries.trouble-free-component]: component did not have forceUpdate method, and error appeared in the render method or didMount method. So error in the component cannot be shown in the interface. Throwing error further.` ); throw e; } } export class TroubleFreeComponent implements ComponentModule<CompatibleComponentInterface<any, any>> { public init(c: CompatibleComponentInterface<any, any>) { listenComponentMethodForErrors(c, "componentWillMount", onErrorFunc); listenComponentMethodForErrors(c, "componentDidMount", onAppearedErrorFunc); listenComponentMethodForErrors(c, "componentWillReceiveProps", onErrorFunc); listenComponentMethodForErrors(c, "shouldComponentUpdate", onErrorFunc); listenComponentMethodForErrors(c, "render", onAppearedErrorFunc); } }