React Suspense无法正常工作

问题描述

我想在提取/未定义Powers时呈现后备组件。我使用以下代码在逻辑中实现了React.Suspense

<Suspense fallback={<p>Loading</p>}>
  <RoutesPowers />
</Suspense>

我的RoutesPowers

const Powers = [ ... ];

const RoutesPowers = () => {

  const [powers,setPowers] = useState(null);
  const fetchPowers = () => setTimeout(() => setPowers(Powers),3000);

  useEffect(() => fetchPowers(),[]);

  return ( powers.map(route => <RoutePowers route={route}/> )

};
            

但是它给了我Cannot read property "map" of null,可能是因为powers为空。这意味着React.Suspense无法正常工作。有人可以帮我吗?

解决方法

为使悬念起作用,距离树较远的组件需要发出承诺。发生这种情况时,悬念将捕获它并显示回退,直到承诺解决为止,然后它将继续呈现其正常子级。您的代码没有任何承诺,因此暂记不做任何事情。

因此,如果您想为此使用暂记,则需要在渲染nig中检测到它的组件没有数据时,让您的组件抛出承诺。然后进行获取,并保存数据,以便在再次安装组件时将具有数据(您无法设置状态,因为在此期间该组件不存在,所以回退了)。

const App = () => (
  <React.Suspense fallback={<p>Loading</p>}>
    <RoutesPowers />
  </React.Suspense>
)

let savedPowers = null;
const fetchPowers = () => {
  return new Promise((resolve,reject) => {
    setTimeout(() => {
      savedPowers = ['first','second']
      resolve();
    },3000)
  });
}

const RoutesPowers = () => {
  const [powers,setPowers] = React.useState(savedPowers);
  if (!powers) {
    throw fetchPowers();
  }

  return powers.map(value => <div key={value}>{value}</div>);
}

ReactDOM.render(<App />,document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.development.js"></script>
<div id="root"></div>

请注意,使用此模式并不常见。更常见的是在一个组件中处理所有内容,如果没有数据则渲染一个占位符,然后开始获取效果,然后在完成后更新状态。您当前的代码已经差不多了,您只需要删除<Suspense>并在RoutesPowers中添加代码即可返回加载段落。

const RoutesPowers = () => {
  const [powers,setPowers] = useState(null);
  const fetchPowers = () => setTimeout(() => setPowers(Powers),3000);

  useEffect(() => fetchPowers(),[]);

  if (!powers) {
    return <p>loading</p>
  }

  return ( powers.map(route => <RoutePowers route={route}/> )

};