React中如何使用import()动态加载组件?

How to use import () to dynamically load components in React?

我尝试用import()代替React.lazy来动态加载组件,但是没用。

App.js

import React, { useState } from 'react';
function App() {
  const [Com, setCom] = useState(null);

  const handleClick = () => {
      import("./A.js").then(c => {
        //console.log(c.default)
        setCom(c.default)
      }) 
  }

  return (
      <div>
        <button onClick={handleClick}>Load</button>
        { Com ? <Com /> : null }
      </div>
   );
}

export default App;

A.js

import React from "react";

export default function A () {
    return (<div>A</div>)
}

Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.

其实我打印出来了c.default。真是个函数

c.default

ƒ A() {
  return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
    __source: {
      fileName: _jsxFileName,
      lineNumber: 4
    },
    __self: this
  }, "A");
}

如果用函数调用setState,它将以先前的值作为参数执行。

const [count,setCount] = useState(0)
setCount(prevCount => prevCount + 1)

在您的情况下,React 不会使用导入的函数更新状态,而是会执行它并将结果设置为状态。

解决方案:

setCom(() => c.default)

实际上,它与动态 import 无关,而与 useState 实施有关。例如:

import Comp from "./A";

function App() {
  const [Com, setCom] = useState(Comp);

  return (
    <div>
      <Com />
    </div>
  );
}

会抛出同样的错误。那是因为当您调用 useState(Comp)Comp "function"(即组件)时(您可以测试它从代码中删除任何 <Com />,添加 console.log里面Aconsole.log还是会发生的)。

因此 Com 不再是一个组件而是一个 JSX 元素。当您尝试以函数方式呈现 JSX 元素时(意味着用 </> 包装它,抛出此错误。

解决方案是将 Com 设置为组件 (() => Com) 或将其呈现为 JSX 子组件 ({Com})

import React, { useState } from "react";

function App() {
  const [Com, setCom] = useState(null);

  const handleClick = () => {
    import("./A.js").then(c => {
      //console.log(c.default)
      setCom(c.default);
    });
  };

  return (
    <div>
      <button onClick={handleClick}>Load</button>
      {/* <Comp /> */}
      {Com}
    </div>
  );
}

export default App;

https://codesandbox.io/s/answer-for-httpsWhosebugcomq62125854863110-jj2wu

顺便说一句,你可以 see the difference 通过 console.dir import Comp from "./A"; 的原始结果和 useState(Comp)

的结果
import Comp from "./A";

function App() {
  const [Com, setCom] = useState(Comp);
  // console.log(1, Com, 2, Comp);
  console.dir(Com) // Object
  console.dir(Comp) // ƒ A()
  //...
}