Criando um Modal em ReactJS
Tags: react, modal, javascript, typescript
Published: 2020-10-20 12:45:18

Preciso de uma janela modal em meu sistema ou site e agora o que fazer? Desenvolver o meu próprio componente ou instalar uma biblioteca inteira só para usar um simples modal?

Muitos escolhem a segunda opção, as vezes pela facilidade de estar pronto, outros por falta de conhecimento para desenvolver o próprio componente. Então decidi compartilhar com vocês um simples exemplo em ReactJS.

```js
import React, { useState, useEffect } from 'react'
import ReactFrom from 'react-dom'

import './modal.css'

import React, { useState, useEffect } from 'react'
import ReactDom from 'react-dom'

import './modal.css'

interface ModalProps {
  isShowing: boolean;
  toggle: () => void;
}

const Modal: React.FC<ModalProps> = ({ isShowing, toggle, children }) => { 
  useEffect(() => {
    const listner = function (e: KeyboardEvent ) {
      if (e.key === 'Escape' || e.key === 'Esc' || e.keyCode === 27) {
        e.preventDefault();
        e.stopPropagation();

        isShowing && toggle();
      }
    }

    window.addEventListener('keyup', listner)

    return (() => {
      window.removeEventListener('keyup', listner)
    })

  }, [isShowing, toggle])

  return (
    isShowing ? ReactDom.createPortal(
      <div className="modal-overlay">
        <div className="modal-wrapper">
          <div className="modal">
            {children}
          </div>
        </div>
      </div>, document.body
    ) : null
  )
}

interface ModalHeaderProps {
  toggle: () => void;
}

export const ModalHeader: React.FC<ModalHeaderProps> = ({ toggle, children }) => (
	<div className="modal-header">
		{children || 'Title'}
    <button 
			className="modal-button-close" 
			data-dismiss="modal" 
			aria-label="Close" 
	    onClick={toggle}
    >
      &times;
    </button>    
	</div>
)

export const ModalBody: React.FC = ({ children }) => (
	<div className="modal-body">
		{children}
	</div>
)

export const ModalFooter: React.FC = ({ children }) => (
	<div className="modal-footer">
		{children}
  </div>
)

export const useModal = () => {
  const [isShowing, setIsShowing] = useState(false);

  function toggle() {
    setIsShowing(!isShowing);
  }

  return {
    isShowing,
    toggle,
  }
}

export default Modal;
```

```css
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1040;
  width: 100vw;
  height: 100vh;
  background-color: rgba(0,0,0,0.5);
}

.modal-wrapper {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1050;
  width: 100%;
  height: 100%;
  overflow-x: hidden;
  overflow-y: auto;
  outline: 0;
}

.modal {
  z-index: 100;
  background: white;
  position: relative;
  margin:20px auto;
  border-radius: 3px;
  max-width: 800px;
  padding: 8px;
  border-radius: 4px;
}

.modal-header {
  display: flex;
  justify-content: space-between;
  border-bottom: 1px solid #ddd;
  padding: 8px 0;
  font-weight: bold;
}

.modal-button-close {
  background: transparent;
  border: none;
  cursor: pointer;
  font-size: 16px;
}

.modal-body {
  padding: 8px 0;
}

.modal-footer {
  display: flex;
  flex-direction: row;
  justify-content: flex-end;
  padding: 8px 0;  
}
```

Agora para usar o componente criado é simples

```js
import React from 'react';
import Modal, {
	ModalHeader, 
	ModalBody, 
	ModalFooter, 
	useModal
} from './components/Modal'

function App() {
  const { isShowing, toggle } = useModal();

  return (
    <div>
      <button onClick={toggle}>
        Modal 
      </button>

      <Modal {...{isShowing, toggle}}>
        <ModalHeader {...{toggle}}>
          My Title
        </ModalHeader>
        <ModalBody>
          Hello World!
        </ModalBody>
        <ModalFooter>
          <button onClick={toggle}>
            Cancel
          </button>
        </ModalFooter>        
      </Modal>
    </div>
  );
}

export default App;
```
![Exemplo](https://dev-to-uploads.s3.amazonaws.com/i/1gvxdjn32g4xbx7379zw.png)

Link do github https://github.com/renatoosaka/useModal