问题描述
我想在提取/未定义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}/> )
};