マウントされたプロミスを作成して呼び出す「アイテム」という名前のコンポーネントがあります。
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はresolveが呼び出されてから6秒後にそれを呼び出します。
画面にそれらの項目を表示することを担当する「リスト」という名前の別のコンポーネントがあります。 「リスト」は「アイテム」コンポーネントの親です。
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)
上記の例では、画面に3つのアイテムが表示されています。
これらのコンポーネントのいずれかを削除すると、componentWillUnmount()が呼び出されますが、削除されたコンポーネントで作成されたpromiseも実行されます。
たとえば、2番目のアイテムを削除しても、2番目のアイテムのプロミスが実行されることがわかります。
unmounted
PROMISE COMPLETED 1
PROMISE COMPLETED 2
PROMISE COMPLETED 3
コンポーネントがアンマウントされると、約束をキャンセルする必要があります。
これのバリエーション 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);
ES6のネイティブプロミスをキャンセルすることはできません。詳しくは https://medium.com/@benlesh/promise-cancellation-is-dead-long-live-promise-cancellation-c6601f1f5082 をご覧ください
しかし、あなたができることは、多分 Bluebird や [〜#〜] q [〜#〜] のようなネイティブでないプロミスライブラリを使用することです。キャンセルされます。
できることはたくさんあります。最も簡単なのは、約束をreject
することです。
this.prom = new Promise((resolve, reject) => {
this.rejectProm = reject;
...
});
その後
componentWillUnmount(){
if (this.rejectProm) {
this.rejectProm();
this.rejectProm = nil;
}
console.log("unmounted")
}
この例ではタイムアウトを使用しているため、アンマウントするときにタイムアウトをクリアする必要があります。
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")
}
私の推測では、これは拒否され、コンソールログは表示されません。