我有一个正常工作的加载组件,它在加载8秒后取消。这段代码有效,但感觉不对我,我想知道是否有更好的方法来做到这一点。
未设置this.mounted
我收到错误:
警告:只能更新已安装或安装的组件。这通常意味着您在已卸载的组件上调用了setState,replaceState或forceUpdate。这是一个无操作。请检查加载组件的代码。
这让我觉得计时器没有被取消所以继续this.seState
。如果我在clearTimeout
中设置componentWillUnmount
,为什么会这样?有没有比使用全局this.mounted
?
class Loading extends Component {
state = {
error: false,
};
componentDidMount = () => {
this.mounted = true;
this.timer();
};
componentWillUnmount = () => {
this.mounted = false;
clearTimeout(this.timer);
};
timer = () =>
setTimeout(() => {
(this.mounted && this.setState({ error: true })) || null;
}, 8000);
render() {
const { showHeader = false } = this.props;
const { error } = this.state;
return (
<View style={backgroundStyle}>
{showHeader && <HeaderShell />}
{!error &&
<View style={loadingHeight}>
<PlatformSpinner size="large" />
</View>}
{error && <Error code="service" />}
</View>
);
}
}
Loading.propTypes = {
showHeader: PropTypes.bool,
};
Loading.defaultProps = {
showHeader: false,
};
export default Loading;
答案 0 :(得分:20)
这让我觉得计时器没有被取消
正如Pointy所说,它不是。您已将功能(this.timer
)传递到clearTimeout
。您需要传递setTimeout
返回值(计时器的句柄),以便您可以使用该句柄取消它。
在这样一个简单的组件中,我没有看到timer
函数的需要,只会增加复杂性;我只是在CDM中设置了计时器:
class Loading extends Component {
state = {
error: false,
};
componentDidMount = () => { // ***
// Remember the timer handle // ***
this.timerHandle = setTimeout(() => { // ***
this.setState({ error: true }); // ***
this.timerHandle = 0; // ***
}, 8000); // ***
}; // ***
// ***
componentWillUnmount = () => { // ***
// Is our timer running? // ***
if (this.timerHandle) { // ***
// Yes, clear it // ***
clearTimeout(this.timerHandle); // ***
this.timerHandle = 0; // ***
} // ***
}; // ***
render() {
const { showHeader = false } = this.props;
const { error } = this.state;
return (
<View style={backgroundStyle}>
{showHeader && <HeaderShell />}
{!error &&
<View style={loadingHeight}>
<PlatformSpinner size="large" />
</View>}
{error && <Error code="service" />}
</View>
);
}
}
Loading.propTypes = {
showHeader: PropTypes.bool,
};
Loading.defaultProps = {
showHeader: false,
};
export default Loading;
但是,如果有比显示更多的逻辑,或仅仅是个人偏好,是的,单独的功能是好的:
class Loading extends Component {
state = {
error: false,
};
componentDidMount = () => {
this.setTimer();
};
componentWillUnmount = () => {
this.clearTimer();
};
setTimer = () => {
if (this.timerHandle) {
// Exception?
return;
}
// Remember the timer handle
this.timerHandle = setTimeout(() => {
this.setState({ error: true });
this.timerHandle = 0;
}, 8000);
};
clearTimer = () => {
// Is our timer running?
if (this.timerHandle) {
// Yes, clear it
clearTimeout(this.timerHandle);
this.timerHandle = 0;
}
};
render() {
const { showHeader = false } = this.props;
const { error } = this.state;
return (
<View style={backgroundStyle}>
{showHeader && <HeaderShell />}
{!error &&
<View style={loadingHeight}>
<PlatformSpinner size="large" />
</View>}
{error && <Error code="service" />}
</View>
);
}
}
Loading.propTypes = {
showHeader: PropTypes.bool,
};
Loading.defaultProps = {
showHeader: false,
};
export default Loading;
答案 1 :(得分:5)
您需要使用setTimeout
中返回的值清除(参见下文)。但是,在clearTimeout
中执行componentWillUnmount
是一种正确的方法,我还没有看到任何人以不同的方式做到这一点。
componentDidMount = () => {
this.mounted = true;
this.timeout = this.timer();
};
componentWillUnmount = () => {
this.mounted = false;
clearTimeout(this.timeout);
};
timer = () =>
setTimeout(() => {
(this.mounted && this.setState({ error: true })) || null;
}, 8000);
答案 2 :(得分:0)
反应16.3:此解决方案对我有用,其他解决方案在我的情况下不起作用:
class Modal extends Component {
constructor(props) {
super(props);
this.timeout = null;
this.state = {
clicked: false,
};
}
handleClick = async (e, action) => {
if (!this.state.clicked) { /
this.setState( {clicked: true} , async () => {
const res = await action();
this.timeout = setTimeout(() => {
if (this.mounted) this.setState( {clicked: false});
this.timeout = null;
}, 2000);
});
}
};
componentDidMount = () => {
this.mounted = true;
};
componentWillUnmount = () =>{
this.mounted = false;
if (this.timeout) {
clearTimeout(this.timeout)
}
};