React Suspense 未按预期工作
React Suspense is not working as intended
我想在 Powers
为 fetched/undefined 时呈现后备组件。我使用以下代码在我的逻辑中实现了 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
没有正常工作。有人可以帮我解决这个问题吗?
要使悬念产生任何效果,树中更靠下的组件需要做出承诺。当这种情况发生时,suspense 将捕获它并显示回退,直到 promise 解决,然后它恢复正常渲染 children。您的代码不提供任何承诺,因此悬念不做任何事情。
所以如果你想为此使用悬念,你需要让你的组件在 rendernig 期间抛出一个承诺,如果它检测到它没有数据。然后做你的抓取,并保存数据,这样当组件再次挂载时它就会有数据(你不能设置状态,因为组件在此期间不存在,回退)。
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 中的代码添加到 return 加载段落。
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}/> )
};
我想在 Powers
为 fetched/undefined 时呈现后备组件。我使用以下代码在我的逻辑中实现了 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
没有正常工作。有人可以帮我解决这个问题吗?
要使悬念产生任何效果,树中更靠下的组件需要做出承诺。当这种情况发生时,suspense 将捕获它并显示回退,直到 promise 解决,然后它恢复正常渲染 children。您的代码不提供任何承诺,因此悬念不做任何事情。
所以如果你想为此使用悬念,你需要让你的组件在 rendernig 期间抛出一个承诺,如果它检测到它没有数据。然后做你的抓取,并保存数据,这样当组件再次挂载时它就会有数据(你不能设置状态,因为组件在此期间不存在,回退)。
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 中的代码添加到 return 加载段落。
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}/> )
};