17
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

2018年のbeforeunloadイベントハンドラーの書き方メモ

Last updated at Posted at 2018-11-20

ブラウザ自身またはタブを閉じる時に、大事な未保存情報がある場合、beforeunloadイベントハンドラーを登録することで、閉じる処理を止めて確認ダイアログを表示することが出来ます。

今回はreactでbeforeunloadハンドラーを書く時にはまったことをメモします。

結論

  • 確認ダイアログの表示・非表示と表示するメッセージのコントロールはbeforeunloadハンドラーのevent.returnValueだけでコントールすれば良い。

  • beforeunloadハンドラーでメッセージ文字列を返すような実装だと、変な動きがあるからです。

環境

  • Win7+IE11
  • MacOS 10.13.5 + Chrome 70.0

reactでの書き方

export default class MyComp extends React.Component {
  constructor(props) {
    super(props);

    this.handleBeforeUnload = this.handleBeforeUnload.bind(this);
  }

  componentWillMount() {
    // 登録
    window.addEventListener('beforeunload', this.handleBeforeUnload);
  }

  componentWillUnmount() {
    // 解除
    window.removeEventListener('beforeunload', this.handleBeforeUnload);
  }

  handleBeforeUnload(e) {
    if (this.props.hogeObject) {
      // 仕様標準のメソッドを呼び出す
      e.preventDefault();
      // returnValueに画面に表示したいメッセージを設定(Chromeはそれを無視してブラウザ定義のメッセージを表示)
      e.returnValue = '未保存のデータがありますが、本当に閉じますか?';
    }
  }
  // ...
}
  • 該当条件に当たった場合、e.returnValueにメッセージ文字列を設定すると、閉じる動作が停止されます。
  • e.preventDefault()が仕様標準のお薦めなので、念のため書きます。

次のような書き方で困った!!!

ネットで調べるとよく出てくる記事には、マルチブラウザをサポートするために、e.returnValueとハンドラーの戻り値を両方返すようなお薦め実装がありますが、実に試してみたら、下記のような変な動きがあることがわかりました。

  • 最初はhogeObjectがない状態で、確認ダイアログなしで、タブを閉じれます。
  • 一旦hogeObjectがある状態にして、タブを閉じると確認ダイアログが表示されます。(ここまでまた良い)
  • 他の画面に遷移してから、もう一回この画面を表示して、hogeObjectない状態でタブを閉じると、確認ダイアログが表示されてしまいます。
  • デバッグしてみたら、handleBeforeUnloadは初回と同じように空白文字列を返しています。
  • 戻り値が空白でも、初回と違って確認ダイアログを表示するのが何故でしょうか?ブラウザがURL単位で覚えたのかな?
  handleBeforeUnload(e) {
    let msg = '';
    if (this.props.hogeObject) {
      // 仕様標準のメソッドを呼び出す
      e.preventDefault();
      // returnValueに画面に表示したいメッセージを設定(Chromeはそれを無視してブラウザ定義のメッセージを表示)
      msg = '未保存のデータがありますが、本当に閉じますか?';
    }

    e.returnValue = msg;
    return msg;
  }

解決

ブラウザの裏仕様がわかりませんが、一旦標準に書いてあるe.returnValueに戻り値を設定するように修正したら、今回の問題を解決しました。

参考ドキュメント

17
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?