在 ReactJS 中卸载组件时取消承诺
Posted
技术标签:
【中文标题】在 ReactJS 中卸载组件时取消承诺【英文标题】:Cancel a promise when a component is unmounted in ReactJS 【发布时间】:2017-11-11 11:18:47 【问题描述】:我有一个名为“Item”的组件,它在挂载后创建并调用一个 Promise。
class Item extends React.Component
constructor(props)
super(props)
this.onClick = this.onClick.bind(this)
this.prom = new Promise((resolve, reject) =>
setTimeout(() => resolve("PROMISE COMPLETED "+this.props.id),6000)
)
componentDidMount()
this.prom.then((success) =>
console.log(success)
)
componentWillUnmount()
console.log("unmounted")
onClick(e)
e.preventDefault()
this.props.remove(this.props.id)
render()
return (
<h1>Item this.props.id - <a href="#" onClick=this.onClick>Remove</a></h1>
)
如您所见,promise 在调用 6 秒后调用 resolve。
还有另一个名为“List”的组件负责在屏幕上显示这些项目。 “List”是“Item”组件的父级。
class List extends React.Component
constructor(props)
super(props)
this.state =
items : [1,2,3]
this.handleRemove = this.handleRemove.bind(this)
handleRemove(id)
this.setState((prevState, props) => (
items : prevState.items.filter((cId) => cId != id)
));
render()
return (
<div>
this.state.items.map((item) => (
<Item key=item id=item remove=this.handleRemove />
))
</div>
)
ReactDOM.render(<List />,root)
在上面的例子中,它在屏幕上显示了三个项目。
如果我删除了这些组件中的任何一个,componentWillUnmount() 将被调用,但已在已删除组件中创建的 promise 也会运行。
例如,即使我删除了第二项,我也可以看到第二项的承诺仍在运行。
unmounted
PROMISE COMPLETED 1
PROMISE COMPLETED 2
PROMISE COMPLETED 3
卸载组件时我必须取消承诺。
【问题讨论】:
我认为我们无法检查这个答案:***.com/questions/30233302/…,也请检查这个:esdiscuss.org/topic/cancellation-architectural-observations 您是否只尝试在this.prom
调用Promise
构造函数一次?
不确定我是否完全理解这个问题,但this fiddle 有帮助吗?第 8 行和第 28 行是要查看的行
【参考方案1】:
https://hshno.de/BJ46Xb_r7 的一个变体似乎对我有用。
我用mounted
实例变量创建了一个HOC,并将所有异步组件包装在其中。
下面是我的代码大致的样子。
export function makeMountAware(Component)
return class MountAwareComponent extends React.Component
mounted = false;
componentDidMount()
this.mounted = true;
componentWillUnmount()
this.mounted = false;
return (
<Component
mounted = this.mounted
...this.props
...this.state
/>
);
class AsyncComponent extends React.Component
componentDidMount()
fetchAsyncData()
.then(data =>
this.props.mounted && this.setState(prevState => (
...prevState,
data
));
);
export default makeMountAware(AsyncComponent);
【讨论】:
这不会导致内存泄漏,因为即使组件被卸载,promise 仍然持有对它的引用?【参考方案2】:您不能取消原生 ES6 承诺。阅读更多https://medium.com/@benlesh/promise-cancellation-is-dead-long-live-promise-cancellation-c6601f1f5082
但是,您可以做的是使用非原生的 promise 库,例如 Bluebird 或 Q,它们会为您提供可以取消的 promise。
【讨论】:
***.com/questions/29478751/… js 承诺只是承诺,不管使用什么库,@chitharanjan-das,你的意思是说原生 js 承诺不能被取消吗?【参考方案3】:您可以做很多事情。最简单的就是reject
promise:
this.prom = new Promise((resolve, reject) =>
this.rejectProm = reject;
...
);
然后
componentWillUnmount()
if (this.rejectProm)
this.rejectProm();
this.rejectProm = nil;
console.log("unmounted")
【讨论】:
【参考方案4】:由于您在此示例中使用了超时,因此您应该在卸载时将其清除。
class Item extends React.Component
constructor(props)
super(props)
this.onClick = this.onClick.bind(this)
// attribute for the timeout
this.timeout = null;
this.prom = new Promise((resolve, reject) =>
// assign timeout
this.timeout = setTimeout(() => resolve("PROMISE COMPLETED "+this.props.id),6000)
)
componentDidMount()
this.prom.then((success) =>
console.log(success)
)
componentWillUnmount()
// clear timeout
clearTimeout(this.timeout);
console.log("unmounted")
我的猜测是这将导致拒绝,并且您不会看到该控制台日志。
【讨论】:
以上是关于在 ReactJS 中卸载组件时取消承诺的主要内容,如果未能解决你的问题,请参考以下文章