8秒間読み込まれたときにキャンセルする作業用の読み込みコンポーネントがあります。このコードは動作しますが、私には気分が悪く、これを行うためのより良い方法があるかどうか疑問に思っています。
this.mounted
を設定しないと、エラーが発生します。
警告:マウントされたコンポーネントまたはマウントされたコンポーネントのみを更新できます。これは通常、マウントされていないコンポーネントでsetState、replaceState、またはforceUpdateを呼び出したことを意味します。これはノーオペレーションです。 Loadingコンポーネントのコードを確認してください。
これは、タイマーがキャンセルされていないので、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;
これにより、タイマーがキャンセルされないように思われます
Pointyが言ったように、そうではありません。 function(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;
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);
React 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)
}
};