LoginSignup
4
4

More than 3 years have passed since last update.

Reactアプリケーション内で枠外クリックで消えるダイアログを作る

Last updated at Posted at 2020-05-12

Reactアプリケーション内で枠外クリックで消えるダイアログを作ることが何回かあったのでTipsとして残しておきます。


import React, {useState, useRef} from 'react';
import './App.css';

const App: React.FC = () => {
  const [dialogOpen, setDialogOpen] = useState<boolean>(false);
  const dialogNode = useRef<HTMLDivElement>(null);

  const handleClickTrigger = () => {
    setDialogOpen(true);
    document.addEventListener('click', documentClickHandler);
  }

  const documentClickHandler = (e: any) => {
    if(dialogNode.current === null) return;
    if(dialogNode.current.contains(e.currentTarget)) return;
    setDialogOpen(false);
    document.removeEventListener('click', documentClickHandler)
  }

  return (
    <div className="app">
      <button
        onClick={() => !dialogOpen && handleClickTrigger()}
        className="trigger"
      >
        Dialog Trigger
      </button>
      {dialogOpen && (
        <div
          ref={dialogNode}
          className="content"
        >
          Dialog Content
        </div>
      )}
    </div>
  );
}

export default App;

スタイル

/* App.css */

.app {
  position: relative;
}

.trigger {
  border: 1px solid #000;
  border-radius: 6px;
  cursor: pointer;
  display: inline-block;
  margin: 10px;
  padding: 10px;
}

.content {
  border: 1px solid #000;
  display: inline-block;
  padding: 36px;
  position: absolute;
  top: 58px;
  left: 26px;
}

おまけ: classコンポーネントで作る場合


import React from 'react';
import './App.css';

class App extends React.Component {
    constructor() {
        super();
        this.state = {
            dialogOpen: false,
        }
        this.dialogNode = null;
    }

    handleClickTrigger() {
        this.setState({dialogOpen: true});
        document.addEventListener('click', this.documentClickHandler);
    }

    documentClickHandler = e => {
        if(this.dialogNode.contains(e.target)) return;
        this.setState({dialogOpen: false}, () => {
            document.removeEventListener('click', this.documentClickHandler);
        })
    }

    render() {
        const {dialogOpen} = this.state;
        return (
            <div className="app">
                <button
                    onClick={() => !dialogOpen && this.handleClickTrigger()}
                    className="trigger"
                >
                    Dialog Trigger
                </button>
                {dialogOpen && (
                    <div
                    ref={node => this.dialogNode = node}
                    className="content"
                    >
                    Dialog Content
                    </div>
                )}
            </div>
        )
    }
}

export default App;
4
4
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
4
4