Vencord/src/utils/lazyReact.tsx

50 lines
1.7 KiB
TypeScript
Raw Normal View History

/*
* Vencord, a Discord client mod
* Copyright (c) 2023 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { makeLazy } from "./lazy";
2024-06-12 20:45:54 +00:00
export type LazyComponentType<T extends object = any> = React.ComponentType<T> & Record<PropertyKey, any>;
export const SYM_LAZY_COMPONENT_INNER = Symbol.for("vencord.lazyComponent.inner");
/**
* A lazy component. The factory method is called on first render.
2024-05-08 09:44:18 +00:00
*
2024-05-03 02:18:12 +00:00
* @param factory Function returning a component
* @param attempts How many times to try to get the component before giving up
* @returns Result of factory function
*/
2024-08-03 19:32:28 +00:00
export function LazyComponent<T extends object = any>(factory: () => LazyComponentType<T>, attempts = 5, errMsg: string | (() => string) = `LazyComponent factory failed:\n\n${factory}`) {
const get = makeLazy(factory, attempts, { isIndirect: true });
2024-05-03 02:18:12 +00:00
let InnerComponent = null as LazyComponentType<T> | null;
2024-05-05 02:56:02 +00:00
let lazyFailedLogged = false;
const LazyComponent = (props: T) => {
2024-05-05 02:56:02 +00:00
if (!get.$$vencordLazyFailed()) {
const ResultComponent = get();
if (ResultComponent != null) {
InnerComponent = ResultComponent;
Object.assign(LazyComponent, ResultComponent);
}
2024-05-05 02:56:02 +00:00
}
2024-05-03 02:18:12 +00:00
if (InnerComponent === null && !lazyFailedLogged) {
if (get.$$vencordLazyFailed()) {
lazyFailedLogged = true;
}
2024-08-03 19:32:28 +00:00
console.error(typeof errMsg === "string" ? errMsg : errMsg());
}
return InnerComponent && <InnerComponent {...props} />;
};
LazyComponent[SYM_LAZY_COMPONENT_INNER] = () => InnerComponent;
return LazyComponent as LazyComponentType<T>;
}