Preact error: "objects are not valid as a child. Encountered an object with the keys {}" when using async await in root component

Preact error: "objects are not valid as a child. Encountered an object with the keys {}" when using async await in root component

我是第一次使用 Preact。

我只是用 preact-cli 和这个默认模板创建了一个新项目:https://github.com/preactjs-templates/default.

app.js 中,我正在尝试使用此代码:

import { Router } from 'preact-router';

import Header from './header';
import Home from '../routes/home';
import Profile from '../routes/profile';

// I added this function
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

const App = async () => { // I added "async" and the "{" in this line
  await sleep(3000) // I added this line

  return ( // I added this line
    <div id="app">
      <Header />
      <Router>
        <Home path="/" />
        <Profile path="/profile/" user="me" />
        <Profile path="/profile/:user" />
      </Router>
    </div>
  )
} // I added this line

export default App;

但不幸的是浏览器给我错误:

Uncaught Error: Objects are not valid as a child. Encountered an object with the keys {}.

为什么?

如果我不使用 async/await,它会起作用。

Reactjs 是一个组件库。它的核心有一个像

这样的功能
React.createElement(component, props, ...children)

这里第一个参数是你要渲染的组件。

当您输入 await sleep(3000) 时,该函数不会返回任何有效的 children/html 对象,而是返回一个空对象。 这就是您收到此错误的原因。

免责声明:我在 Preact 上工作。

我们的调试插件 (preact/debug) 将在作为子对象传递的无效对象与 h/createElement 的预期 return 类型不匹配时打印此错误,通常称为vnode:

const invalidVNode = { foo: 123 };
<div>{invalidVNode}</div>

在你的例子中,你的组件函数 return 是一个 Promise,它是 JavaScript 中的一个对象。当 Preact 渲染该组件时,渲染函数不会 return 一个 vnode,而是一个 Promise。这就是错误发生的原因。

提出的问题:

如何进行异步初始化?

一旦触发,Preact 中的渲染过程始终是同步的。 return 是 Promise 的组件违反了该合同。这样做的原因是因为您通常希望在异步初始化发生时至少向用户显示一些东西,例如微调器。例如,现实世界的场景是通过网络获取数据。

import { useEffect } from "preact/hooks";

const App = () => {
  // useEffect Hook is perfect for any sort of initialization code.
  // The second parameter is for checking when the effect should re-run.
  // We only want to initialize once when the component is created so we
  // pass an empty array so that nothing will be dirty checked.
  useEffect(() => {
    doSometThingAsyncHere()
  }, []);

  return (
    <div id="app">
      <Header />
      <Router>
        <Home path="/" />
        <Profile path="/profile/" user="me" />
        <Profile path="/profile/:user" />
      </Router>
    </div>
  )
}