- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
通常当我返回一个依赖于获取数据的组件(我使用的是 nextjs 13)时,我有条件地渲染元素以确保值可用:
表格组件:
export const Table = ({ ...props }) => {
const [tableEvents, setTableEvents] = useState(null);
useEffect(() => {
fetchAndSetTableEvents();
}, []);
async function fetchAndSetTableEvents() {
const fetchedEvents = await fetch(* url and params here *)
if (fetchedEvents && fetchedEvents) {
setTableEvents(fetchedEvents);
} else {
setTableEvents(null);
}
}
return (
<React.Fragment>
<div>
{tableEvents ? tableEvents[0].title : null}
</div>
</React.Fragment>
)
};
如果我尝试使用 Suspense 从父组件加载 TableComponent,它会加载但不会在加载前显示回退:
<Suspense fallback={<div>Loading Message...</div>}>
<TableComponent />
</Suspense>
但是,如果我删除 TableComponent 中的条件呈现并仅指定变量,则回退会在尝试加载组件时正确显示:
return (
<React.Fragment>
<div>
{tableEvents[0].title}
</div>
</React.Fragment>
)
但它最终无法加载组件,因为 tableEvents 最初为 null 并且会在每次提取时发生变化,因此它不能具有可预测的键。
React docs对于 Suspense,只显示一个像这样的简单示例。
有条件地返回render也返回组件ok但是没有显示suspense fallback
if (tableEvents) {
return (
<React.Fragment>
<div>
{tableEvents[0].event_title}
</div>
</React.Fragment>
)
}
我如何在组件中获取和返回值,这些值可能存在也可能不存在,满足加载时显示的 Suspense 回退标准。我假设它以一种我正在阻止但找不到解决方法的方式依赖于 Promise。
最佳答案
要触发Suspense
,其中一个 child 必须throw
一个Promise
。此功能更多地针对库开发人员,但您仍然可以尝试自己实现一些功能。
基本思想很简单,这是伪代码
function ComponentWithLoad() {
const promise = fetch('/url') // create a promise
if (promise.pending) { // as long as it's not resolved
throw promise // throw the promise
}
// otherwise, promise is resolved, it's a normal component
return (
<p>{promise.data}</p>
)
}
当 Suspense
边界被抛出 Promise
时,它将等待它,并在 promise 解决时重新渲染组件。就这样。
除了现在我们有 2 个问题:
fetch
实际上会创建一个新 promise,它将再次被抛出,我们将永远循环...这两个问题的解决方案是找到一种方法将 promise 存储在 Suspense
边界之外(并且很可能完全在 react 之外)。
async
获取promise状态首先,让我们围绕任何允许我们获取其状态(待处理、已解决、已拒绝)或已解决数据的 promise 编写一个包装器。
const promises = new WeakMap()
function wrapPromise(promise) {
const meta = promises.get(promise) || {}
// for any new promise
if (!meta.status) {
meta.status = 'pending' // set it as pending
promise.then((data) => { // when resolved, store the data
meta.status = 'resolved'
meta.data = data
})
promise.catch((error) => { // when rejected store the error
meta.status = 'rejected'
meta.error = error
})
promises.set(promise, meta)
}
if (meta.status === 'pending') { // if still pending, throw promise to Suspense
throw promise
}
if (meta.status === 'error') { // if error, throw error to ErrorBoundary
throw new Error(meta.error)
}
return meta.data // otherwise, return resolved data
}
通过在每次渲染时调用此函数,我们将能够在没有任何 async
的情况下获取 promise 的数据。然后 React Suspense
会在需要时重新渲染。这就是它的作用。
Promise
然后我们只需要将我们的 promise 存储在 Suspense
边界之外。最简单的例子是在父级中声明它,但理想的解决方案(避免在父级本身重新呈现时创建新的 promise )将它存储在 react 本身之外。
export default function App() {
// create a promise *outside* of the Suspense boundary
const promise = fetch('/url').then(r => r.json())
// Suspense will try to render its children, if rendering throws a promise, it'll try again when that promise resolves
return (
<Suspense fallback={<div>Loading...</div>}>
{/* we pass the promise to our suspended component so it's always the same `Promise` every time it re-renders */}
<ComponentWithLoad promise={promise} />
</Suspense>
)
}
function ComponentWithLoad({promise}) {
// using the wrapper we declared above, it will
// - throw a Promise if it's still pending
// - return synchronously the result of our promise otherwise
const data = wrapPromise(promise)
// we now have access to our fetched data without ever using `async`
return <p>{data}</p>
}
WeakMap
非常适合在 promise
和关于此 promise 的一些元数据(状态、返回数据等)之间进行映射,因为一旦 promise
本身在任何地方都没有被引用,元数据可用于垃圾收集Suspense
边界的渲染树中的任何组件都会抛出一个 promise ),它会在每次“尝试”后被 react 卸载渲染。这意味着您不能使用 useState
或 useRef
来保存 promise 或其状态。Map
和获取该端点的 Promise
一样简单,并且只会随着重新获取、缓存控制、 header 、请求参数而变得更加复杂... 这就是为什么我的示例只创建一次简单的 promise 。当使用 Suspense
时,Suspense 节点内的任何树都不会被渲染,同时它仍然抛出一个 Promise。如果您需要同时渲染某些东西,这就是 fallback
属性的用途。
它确实需要我们改变我们对组件分割的思考方式
关于javascript - 有条件地返回 React 组件以满足 Suspense 回退,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75288420/
如何在 2014-10-04 - 2014-10-30 仅工作日和 08.00 - 20.00 之间随机更新日期列? 2014-10-04 - 2014-10-30 random working-da
我有一个二维 (3x7) 数组,我想转换为一维数组,以便我提供的行位于中心。行值可能沿途变化,但必须位于中心。 #define numRows 3 #define numCols 7 #define
我有2张 table : 第一个是“人”: person_id, 人名 第二个是“PersonsGraphs”: person_id1, person_id2, 关系类型 我正在寻找一种建立“家谱”的
是否可以在序列化 JSON 响应的同时根据 If 条件排除某些元素? if(a == 1) { //show element } else { //don't show element }
是否可以在序列化 JSON 响应的同时根据 If 条件排除某些元素? if(a == 1) { //show element } else { //don't show element }
尝试使用 jQuery 编写一个条件,该条件基本上说明,如果 div.gathering 不包含 a.cat-link,则执行以下操作。我已经尝试过以下方法,但似乎不起作用。有人能解释一下吗? if(
该练习要求插入值 x 的副本(这也是要在列表中搜索的值),但前提是该位置是另一个值 n 的倍数。未指定副本应插入到 x 值之前还是之后。 我的问题是并非在所有情况下都插入副本。我认为问题在于,当我插入
我遇到了这个[问题]:How can I store values into a multi-parameter struct and pass typedef struct to a functio
出于某种原因,当我编写 getWinner() 时,它仅适用于 2 种情况(最后一行)。就对角线和列而言,我拥有其他一切,但第 2 行(嗯,三,但数组,所以 2)基本上只适用于 o。只有当 o 位于
我有一个问题。 我想将“guid”列中的值复制到“帖子内容” 所有行都在一个表“wp-posts”中 “postparent”列中的一行有一个值,而“ID”列中的另一项也有相同的值 我必须做的事情是
我想将两个像这样的表合并到一个表中,并为重复的键行添加合并表中最旧的 DateAdded 值。 (Key1,Key2) 是主键。 +-----------+-----------+------+---
通过下面的表格和数据,我试图获得最高的 effective_from每个唯一 brand 小于当前时间戳的值/model组合 - 实际上是每件商品的当前价格。 CREATE TABLE things
您能告诉我如何删除未知号码的最后一条记录(有条件)吗? 例如,在这种情况下我想删除id为6到10的记录。 注意:该表和记录不是恒定的。 +----+-----+---------+ | id | ur
这个问题不太可能对任何 future 的访客有帮助;它只与一个较小的地理区域、一个特定的时间点或一个非常狭窄的情况相关,通常不适用于全世界的互联网受众。如需帮助使此问题更广泛适用,visit the
我有两个表, 标签 -> id,name,description,user,status 标签_连接。 -> id, Label_id, 类别 所以有多个类别,假设 1 => 新的,2 => 旧的。
好的,我会长话短说。 这是我的代码 String s = edittextkata.getText().toString(); String[] vowels = {"a","
我有一个非常具体的要求,我发现很难做到,我需要查找并替换文件中的某些行,但问题是文本不同,唯一的好处是它们都有一个 .[扩展名] 例如: 30/07/2012 14:46 17
我有一个大型数据库,其中存在各种不一致之处。我想澄清的项目之一是根据人口更改国家/地区状态。 数据样本是: { "_id" : "D", "name" : "Deutschland", "pop" :
我需要将范围(有条件)中的唯一值组合到同一行的另一个范围中。 其实我前两天发过类似的问题Link所提供的答案在我提出上述问题时有效。 但后来,我遇到了一个新问题,我宁愿问一个新的问题,让它更清楚: (
我刚开始使用 VBA,并且正在努力处理需要清理的工作表。 我有一列包含混合邮政编码和城市名称的字符串。我想从 A 列中提取邮政编码并放在 B 列中,并在 C 列中提取带有下划线的城市名称。 我的(示例
我是一名优秀的程序员,十分优秀!