带有React Suspense的组件导致Eternal Loop



我正在学习React,并尝试使用Suspense。

在第一个游戏中,我尝试使用包装的promise对象作为道具
包装程序在未解决时抛出承诺。它永远循环
然后我用useEffect试试,但它也有同样的问题。

这是我的代码和沙盒。请教我如何解决这个问题。

textsandbox EternalLoop
*useEffect块注释在sandbox中被丢弃,因为它永远循环。

import React, { Suspense, useEffect, useState } from "react";
const lazyTimer = () => {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(" from 10sec past");
}, 1000);
});
return promise;
};
const wrapPromise = promise => {
let status = "pending";
let result;
console.log("looping....");
const suspender = promise.then(
r => {
status = "fulfilled";
result = r;
},
e => {
status = "rejected";
result = e;
}
);
const read = () => {
if (status === "pending") {
throw suspender;
} else if (status === "rejected") {
throw result;
} else {
return result;
}
};
return { read };
};
const Hallo = () => {
const [text, setText] = useState("your on time");
// useEffect(
//   setText(
//     wrapPromise(lazyTimer()).read()
//   ), [text],
// );
return <h2>hello world, {text}</h2>;
};
export default function App() {
return (
<div className="App">
<Suspense fallback={<p>Loading...</p>}>
<Hallo />
</Suspense>
</div>
);
}

编辑3:让我感到困惑的是,它的工作原理,我没有看到任何文档。IE,孩子们是怎么工作的。在我看来,你在文档中查看演示的代码时做出了承诺。但我在任何地方都没有看到这方面的记录。

因此,您抛出一个承诺,即当解析时,您的组件现在已经准备好了(即定时器承诺-或Apollo客户端承诺-获取承诺等(。当该承诺解析时,组件现在可以挂载了。我喜欢它,如果我对它的工作原理是正确的,我希望它能被清楚地记录下来。


这个问题与悬念无关。您的代码:

const Hallo = () => {
const [text, setText] = useState("your on time");
useEffect(
//   setText(
//     wrapPromise(lazyTimer()).read()
//   ), [text],
// );
return <h2>hello world, {text}</h2>;
};

有这个问题。它运行setText,然后将text作为依赖项。因此,您更改了text,然后它再次运行,因为text发生了更改。因此产生了无限循环。

你有3种方法来修复这个

1( 做一些if语句,使其不是一个无限循环(即,您知道什么文本不应该是,或者检查它是否相同(。

2( 从依赖项列表中删除text(错误!(

3( 通过使用替代setText方法将其移除,将其作为函数调用,而不是提供值。请参阅此处获取文档。

useEffect(
setText(text => wrapPromise(lazyTimer()).read())
), [],
);

则CCD_ 8将不是依赖项。

我推荐3。


编辑:

最重要的是,您使用的包装器不正确。我看了你可能使用的教程和它的Github。他们创建了包装。然后在数据获取部分(计时器(将它们的promise包装在promise包装器中。

我试图使用useEffect:使您的代码尽可能相似

import React, { Suspense, useEffect, useState } from "react";
import "./styles.css";
const wrapPromise = promise => {
let status = "pending";
let result;
console.log(`looping.... + ${new Date().toString()}`);
const suspender = promise.then(
r => {
status = "fulfilled";
result = r;
},
e => {
status = "rejected";
result = e;
}
);
const read = () => {
if (status === "pending") {
throw suspender;
} else if (status === "rejected") {
throw result;
} else {
return result;
}
};
return { read };
};
const lazyTimer = () => {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(" from 10sec past");
}, 10000);
});
return wrapPromise(promise);
};
const data = lazyTimer();
const Hallo = () => {
const [text, setText] = useState(data.read());
useEffect(() => {
console.log("Im running");
setText(data.read());
}, []);
return <h2>hello world, {text}</h2>;
};
export default function App() {
return (
<div className="App">
<Suspense fallback={<p>Loading...</p>}>
<Hallo />
</Suspense>
</div>
);
}

这是有效的。这里是沙盒。

值得注意的是,光环可能只是:

const Hallo = () => {
const text = data.read()
return <h2>hello world, {text}</h2>;
};

最新更新