【问题标题】:React Suspense is not working as intendedReact Suspense 没有按预期工作
【发布时间】:2020-12-10 12:37:11
【问题描述】:

当我的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 无法正常工作。有人可以帮我解决这个问题吗?

【问题讨论】:

  • 不是悬念问题 是因为useState默认初始化powers值导致的javascript错误。尝试使用空数组,例如 const [powers, setPowers] = useState([]);
  • 哦,是的,我的错。虽然还没有修好。当我使用 React DevTools 分析 元素的悬念时,它一直显示suspense: false,我没有看到我的回调元素而不是 ,我只看到一个空的 跨度>

标签: reactjs async-await react-suspense


【解决方案1】:

为了让悬念产生任何效果,树下更远的组件需要抛出一个 Promise。当这种情况发生时,suspense 将捕获它并显示回退,直到 promise 解决,然后它继续渲染它的正常子级。您的代码不会抛出任何承诺,因此 suspense 不会做任何事情。

所以如果你想为此使用 suspense,你需要让你的组件在 rendernig 检测到它没有数据时抛出一个 Promise。然后进行获取,并保存数据,这样当组件再次挂载时它就会有数据(您不能设置状态,因为在此期间组件不存在,回退存在)。

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>

请注意,使用这种模式并不常见。更常见的是在一个组件中处理所有内容,如果没有数据则呈现占位符,然后在效果中启动 fetch,然后在完成时更新状态。您当前的代码几乎就在那里,您只想删除 &lt;Suspense&gt; 并在 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}/> )

};

【讨论】:

  • 谢谢你,尼克!您不仅解决了我的问题,还提出了更好的模式。
猜你喜欢
  • 1970-01-01
  • 2017-04-04
  • 2021-09-03
  • 1970-01-01
  • 2022-08-16
  • 2020-08-04
  • 2019-01-19
  • 2022-01-11
  • 2018-03-25
相关资源
最近更新 更多