React 组件各生命周期中均没有对刷新事件的监听与响应,还需依赖原始的 window的 beforeunload事件,具体实现如下
import React, { Component } from 'react';
export default class Demo extends Component {
constructor(props) {
super(props);
this.state = {};
}
componentDidMount() {
// do something
// ...
// It's best to write on the last line
window.addEventListener('beforeunload', this.beforeUnload);
}
componentWillUnmount() {
// It's best to write on the first line
window.removeEventListener('beforeunload', this.beforeUnload);
// ...
// do something
}
beforeUnload = e => {
e.preventDefault();
// It may not appear on the interceptor window
e.returnValue = '';
};
render() {
return <></>;
}
}
但
使用中,发现刷新事件和卸载事件 setState 在执行上略有不同
具体,看下测试用例
import React, { Component } from 'react';
import moment from 'moment';
export default class Demo extends Component {
constructor(props) {
super(props);
this.state = { status: '' };
}
componentDidMount() {
window.addEventListener('beforeunload', this.beforeUnload);
}
componentWillUnmount() {
window.removeEventListener('beforeunload', this.beforeUnload);
this.setState({ status: `will unmount` }, () => {
sessionStorage.setStateThen = JSON.stringify(this.state);
});
sessionStorage.setStateAfter = JSON.stringify(this.state);
}
beforeUnload = e => {
this.setState({ status: `will unload` }, () => {
sessionStorage.setStateThen = JSON.stringify(this.state);
});
sessionStorage.setStateAfter = JSON.stringify(this.state);
// e.preventDefault();
// e.returnValue = '';
};
handleClick = e => {
this.setState({ status: `on click` }, () => {
sessionStorage.setStateThen = JSON.stringify(this.state);
});
sessionStorage.setStateAfter = JSON.stringify(this.state);
};
render() {
let time = moment().valueOf() + 3000;
while (moment().valueOf() < time) {
// do nothing
}
return <button onClick={this.handleClick}>点我</button>;
}
}
(1)清空缓存后,点击事件响应后,控制台输出显示如下
$ sessionStorage.setStateThen
"{'status':'on click'}"
$ sessionStorage.setStateAfter
"{'status':''}"
(2)清空缓存后,卸载事件响应后,控制台输出显示如下
$ sessionStorage.setStateThen
undefined
$ sessionStorage.setStateAfter
"{'status':''}"
(3)清空缓存后,刷新事件响应后,控制台输出显示如下
$ sessionStorage.setStateThen
"{'status':'will unload'}"
$ sessionStorage.setStateAfter
"{'status':'will unload'}"
单就现象来看
结论
普通渲染 setState 异步执行,刷新事件 setState 同步执行,卸载事件 阻止了 setState 的执行
等有时间了,我再翻翻资料,佐证一下这里的结论