如何为 React.lazy 个组件输入自定义的 `preload` 方法?
How to type custom `preload` method for React.lazy components?
当尝试为 React.lazy()
个组件实现 preload()
方法时,典型的模式类似于
const ReactLazyPreload = (importStatement) => {
const Component = React.lazy(importStatement);
Component.preload = importStatement; // Property 'preload' does not exist on type 'LazyExoticComponent<T>'.
return Component;
};
以后可以使用,例如
const MyComponent = ReactLazyPreload(() => import("./MyComponent.tsx");
const onHover = () => { MyComponent.preload() };
但是,第一个代码段第 3 行的赋值导致 TS 错误,
Property 'preload' does not exist on type 'LazyExoticComponent<T>'.
我一直在尝试 declare
,但未能成功消除错误。 preload()
方法应该使用什么类型?
// extend lazy component with `preload` property
interface LazyPreload<Props>
extends React.LazyExoticComponent<React.ComponentType<Props>> {
preload: () => {};
}
function ReactLazyPreload<Props>(
importStatement: () => Promise<{ default: React.ComponentType<Props> }>
) {
// use Object.assign to set preload
// otherwise it will complain that Component doesn't have preload
const Component: LazyPreload<Props> = Object.assign(
React.lazy(importStatement),
{
preload: importStatement,
}
);
return Component;
}
TypeScript 正在努力防止您在此处犯错。
仅仅因为其他人遵循惯例并不能使它成为一个好的约定:在这种情况下,它不是一个安全的约定。 一般来说,改变你不拥有的东西是不安全的。
虽然我在当前版本标签 (17.0.2
) 的 React 代码库中找不到任何似乎会导致向 preload
属性 分配内容的问题一个惰性组件,这并不意味着 React 维护者不会在后续版本中使用这个 属性。如果发生这种情况,并且您覆盖了 属性,则会出现不可预知的行为。
不是改变组件,只是return它旁边的预加载函数:
import {default as React, lazy} from 'react';
import type {ComponentType, LazyExoticComponent} from 'react';
export type ReactLazyFactory<T = any> = () => Promise<{default: ComponentType<T>}>;
export type ComponentPreloadTuple<T = any> = [
component: LazyExoticComponent<ComponentType<T>>,
preloadFn: () => void,
];
export function getLazyComponentWithPreload <T = any>(componentPath: string): ComponentPreloadTuple<T>;
export function getLazyComponentWithPreload <T = any>(factory: ReactLazyFactory<T>): ComponentPreloadTuple<T>;
export function getLazyComponentWithPreload <T = any>(input: string | ReactLazyFactory<T>): ComponentPreloadTuple<T> {
const factory = () => typeof input === 'string' ? import(input) : input();
return [lazy(factory), factory];
}
// ----------
// Example.tsx
export type ExampleProps = {
text: string;
};
export default function ExampleComponent ({text}: ExampleProps) {
return <div>{text}</div>;
}
// ----------
// AnotherComponent.tsx
// use with path to component:
const [Example1, preloadExample1] = getLazyComponentWithPreload<ExampleProps>('./Example');
// use with factory function:
const [Example2, preloadExample2] = getLazyComponentWithPreload<ExampleProps>(() => import('./Example'));
当尝试为 React.lazy()
个组件实现 preload()
方法时,典型的模式类似于
const ReactLazyPreload = (importStatement) => {
const Component = React.lazy(importStatement);
Component.preload = importStatement; // Property 'preload' does not exist on type 'LazyExoticComponent<T>'.
return Component;
};
以后可以使用,例如
const MyComponent = ReactLazyPreload(() => import("./MyComponent.tsx");
const onHover = () => { MyComponent.preload() };
但是,第一个代码段第 3 行的赋值导致 TS 错误,
Property 'preload' does not exist on type 'LazyExoticComponent<T>'.
我一直在尝试 declare
,但未能成功消除错误。 preload()
方法应该使用什么类型?
// extend lazy component with `preload` property
interface LazyPreload<Props>
extends React.LazyExoticComponent<React.ComponentType<Props>> {
preload: () => {};
}
function ReactLazyPreload<Props>(
importStatement: () => Promise<{ default: React.ComponentType<Props> }>
) {
// use Object.assign to set preload
// otherwise it will complain that Component doesn't have preload
const Component: LazyPreload<Props> = Object.assign(
React.lazy(importStatement),
{
preload: importStatement,
}
);
return Component;
}
TypeScript 正在努力防止您在此处犯错。
仅仅因为其他人遵循惯例并不能使它成为一个好的约定:在这种情况下,它不是一个安全的约定。 一般来说,改变你不拥有的东西是不安全的。
虽然我在当前版本标签 (17.0.2
) 的 React 代码库中找不到任何似乎会导致向 preload
属性 分配内容的问题一个惰性组件,这并不意味着 React 维护者不会在后续版本中使用这个 属性。如果发生这种情况,并且您覆盖了 属性,则会出现不可预知的行为。
不是改变组件,只是return它旁边的预加载函数:
import {default as React, lazy} from 'react';
import type {ComponentType, LazyExoticComponent} from 'react';
export type ReactLazyFactory<T = any> = () => Promise<{default: ComponentType<T>}>;
export type ComponentPreloadTuple<T = any> = [
component: LazyExoticComponent<ComponentType<T>>,
preloadFn: () => void,
];
export function getLazyComponentWithPreload <T = any>(componentPath: string): ComponentPreloadTuple<T>;
export function getLazyComponentWithPreload <T = any>(factory: ReactLazyFactory<T>): ComponentPreloadTuple<T>;
export function getLazyComponentWithPreload <T = any>(input: string | ReactLazyFactory<T>): ComponentPreloadTuple<T> {
const factory = () => typeof input === 'string' ? import(input) : input();
return [lazy(factory), factory];
}
// ----------
// Example.tsx
export type ExampleProps = {
text: string;
};
export default function ExampleComponent ({text}: ExampleProps) {
return <div>{text}</div>;
}
// ----------
// AnotherComponent.tsx
// use with path to component:
const [Example1, preloadExample1] = getLazyComponentWithPreload<ExampleProps>('./Example');
// use with factory function:
const [Example2, preloadExample2] = getLazyComponentWithPreload<ExampleProps>(() => import('./Example'));