reactjs - React 中的延迟加载路由与 Typescript AsyncComponent

标签 reactjs typescript lazy-loading react-router-v4 dynamic-import

我正在尝试通过实现 AsyncCompoment 类来在 React 中延迟加载路由,如此处所述 Code Splitting in Create React App .下面是教程中的 es6 asyncComponent 函数:

import React, { Component } from "react";

    export default function asyncComponent(importComponent) {
      class AsyncComponent extends Component {
        constructor(props) {
          super(props);

          this.state = {
            component: null
          };
        }

        async componentDidMount() {
          const { default: component } = await importComponent();

          this.setState({
            component: component
          });
        }

        render() {
          const C = this.state.component;

          return C ? <C {...this.props} /> : null;
        }
      }

      return AsyncComponent;
    }

我已经用 typescript 编写了这个函数,可以确认组件确实被延迟加载了。我面临的问题是它们没有被渲染。我能够确定组件对象在 componentDidMount Hook 中始终未定义:

//AsyncComponent.tsx
async componentDidMount() {
              const { default: component } = await importComponent();

              this.setState({
                component: component
              });
            }

从 importComponent 函数返回的对象具有以下属性:

{
MyComponent: class MyComponent: f,
__esModule: true
}

我修改了 componentDidMount 方法以获取此对象的第一个属性,即 MyComponent 类。进行此更改后,我的项目现在可以延迟加载组件并正确渲染它们。

async componentDidMount() {
          const component = await importComponent();

          this.setState({
            component: component[Object.keys(component)[0]]
          });
        }

我最好的猜测是我没有用 typescript 正确地写下这一行:

const { default: component } = await importComponent();

我像这样调用 asyncComponent 方法:

const MyComponent = asyncComponent(()=>import(./components/MyComponent));

有人知道如何在 typescript 中实现 AsyncComponent 吗?我不确定简单地获取 esModule 对象上的 0 索引是否是正确的方法。

最佳答案

// AsyncComponent.tsx
import * as React from "react";

interface AsyncComponentState {
  Component: null | JSX.Element;
};
interface IAsyncComponent {
  (importComponent: () => Promise<{ default: React.ComponentType<any> }>): React.ComponentClass;
}

const asyncComponent: IAsyncComponent = (importComponent) => {
  class AsyncFunc extends React.PureComponent<any, AsyncComponentState> {
    mounted: boolean = false;
    constructor(props: any) {
      super(props);

      this.state = {
        Component: null
      };
    }
    componentWillUnmount() {
      this.mounted = false;
    }
    async componentDidMount() {
      this.mounted = true;
      const { default: Component } = await importComponent();
      if (this.mounted) {
        this.setState({
          component: <Component {...this.props} />
        });
      }

    }


    render() {
      const Component = this.state.Component;
      return Component ? Component : <div>....Loading</div>
    }
  }
  return AsyncFunc;

}
export default asyncComponent;


// Counter.tsx

import * as React from 'react';
import { RouteComponentProps } from 'react-router';

interface CounterState {
  currentCount: number;
}

class Counter extends React.Component<RouteComponentProps<{}>, CounterState> {
  constructor() {
    super();
    this.state = { currentCount: 0 };
  }

  public render() {
    return <div>
      <h1>Counter</h1>

      <p>This is a simple example of a React component.</p>

      <p>Current count: <strong>{this.state.currentCount}</strong></p>

      <button onClick={() => { this.incrementCounter() }}>Increment</button>
    </div>;
  }

  incrementCounter() {
    this.setState({
      currentCount: this.state.currentCount + 1
    });
  }
}
export default Counter;

//routes.tsx
import * as React from 'react';
import { Route } from 'react-router-dom';
import { Layout } from './components/Layout';
import { Home } from './components/Home';
import asyncComponent from './components/AsyncComponent';


const AsyncCounter = asyncComponent(() => import('./components/Counter'));

export const routes = <Layout>
  <Route exact path='/' component={Home} />
  <Route path='/counter' component={AsyncCounter} />
</Layout>;

关于reactjs - React 中的延迟加载路由与 Typescript AsyncComponent,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47057715/

相关文章:

javascript - React Native - 复选框无法取消选中 "checked"框

node.js - 使用 Sequelize.js 和 PostgreSQL 查询关联模型上的 JSONB 字段

html - 为什么加载属性在 chrome 中不起作用?

java - 有没有办法避免 Jackson 序列化未获取的惰性属性

javascript - 期望在箭头函数的末尾返回一个值 array-callback-return on filter function

javascript - "A valid React element (or null) must be returned."与 array.map

javascript - 错误 : Cannot invoke an expression whose type lacks a call signature

Typescript promise 输入 then

angular - 在angular-cli中创建模块时生成路由模块

reactjs - React Redux Material-ui - 制作带有可编辑单元格的表格