簡體   English   中英

如何為 React.lazy 組件鍵入自定義的“預加載”方法?

[英]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 維護者贏了'不要在后續版本中使用此屬性。 如果發生這種情況,並且您覆蓋了該屬性,則會出現不可預測的行為。

無需更改組件,只需在其旁邊返回預加載 function :

TS Playground 鏈接

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'));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM