【问题标题】:Lazy Loading Routes in React With Typescript AsyncComponent使用 Typescript AsyncComponent 在 React 中延迟加载路由
【发布时间】:2017-11-01 14:57:33
【问题描述】:

我正在尝试通过实现 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 挂钩中始终未定义:

//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]]
          });
        }

我最好的猜测是我没有在打字稿中正确写下这一行:

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

我这样调用 asyncComponent 方法:

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

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

【问题讨论】:

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


    【解决方案1】:
    // 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>;
    

    【讨论】:

    • 如何将 props 传递给异步组件?
    猜你喜欢
    • 2019-04-23
    • 2020-05-31
    • 1970-01-01
    • 1970-01-01
    • 2015-03-28
    • 2017-05-19
    • 2017-05-25
    • 1970-01-01
    • 2018-05-22
    相关资源
    最近更新 更多