Modais com React js
Tags: react, typescript, javascript
Published: 2021-01-29 00:44:52

A ideia por trás deste tutorial é a criação de um código dinâmico de modais em React js com a ajuda do Context. Aqui está um exemplo do que eu estou falando.

![modal](https://dev-to-uploads.s3.amazonaws.com/i/5wbeqnando85nquqs3g0.gif)

#### Componente da Modal

O componente da modal que é um Portal , recebe do Context o apelido da modal que deve ter o estado alterado e a sua ação que é abrir ou fechar, e do seu componente pai ela recebe o children(jsx a ser renderizado) e o apelido do mesmo, para verificar se é essa modal mesmo que o evento está chamando.

```javascript
import React, { useContext } from "react";
import ReactDOM from "react-dom";
import { ModalContext } from "../context/modal-context";
import { ModalContainer } from "./modal-styles";

interface ModalContextProps {
    isShowing: any;
    handleModal: any;
}

const Modal = ({children, alias}: any) => {
  const { isShowing } = useContext<ModalContextProps>(ModalContext); 
  let arrayModal;
  
  isShowing.forEach((modal: any) => {      
    if (modal.action === 'open' && alias === modal.alias) {        
        arrayModal = (<ModalContainer>{children}</ModalContainer>
      );
    }
  });  

  return isShowing.length ? ReactDOM.createPortal(arrayModal, document.body) : null;
};

export default Modal;
```

#### Página

O página é responsável por enviar o evento que irá chamar ás modais, ela também é responsável por conter o componente que a modal vai renderizar, mencionado anteriormente o children, também é necessário que todo o componente de modal utilizado tenha o seu apelido declarado, como forma de identificação.

```javascript
import React, { useContext } from 'react';
import { Container} from './home-styles';
import { ModalContext } from '../../context/modal-context';
import Modal from "../../components/modal";
import FirstPortal from "../portal/first-portal/first-portal";
import SecondPortal from '../portal/second-portal/second-portal';
import ThirdPortal from '../portal/third-portal/third-portal';

const FormDynamic: React.FC = () => {
  
  const { handleModal } = useContext(ModalContext);
  
  return (
    <Container>
       <button
          onClick={() => handleModal('open', 'first-modal')}>
            Abrir primeira modal
        </button>
       <button
          onClick={() => handleModal('open', 'second-modal')}>
            Abrir segunda modal
        </button>
       <button
          onClick={() => handleModal('open', 'third-modal')}>
            Abrir terceira modal
        </button>

        <Modal alias='first-modal'>
          <FirstPortal/>
        </Modal>
        <Modal alias='second-modal'>
          <SecondPortal/>
        </Modal>
        <Modal alias='third-modal'>
          <ThirdPortal/>
        </Modal>
  </Container>
  );
}

export default FormDynamic;
```

#### Conteúdo da modal

O conteúdo a ser renderizado na modal contém tudo o que deve ser exibido ao abrir a modal.

```javascript
import React, { useContext } from 'react';
import { Portal } from '../portal-styles';
import { RiCloseLine } from "react-icons/ri";
import { ModalContext } from '../../../context/modal-context';

const FirstPortal: React.FC = () => {
  const { handleModal } = useContext(ModalContext);

  return (
  <Portal>
      <RiCloseLine onClick={() => handleModal('close', 'first-modal')}/>
      <h1>Primeira Modal</h1>
      <span>😃</span>
  </Portal>);
}

export default FirstPortal;
```

#### Hooks

O hook useModal é reponsável por armazenar os estados e as funções que irão acionar a modal.

```javascript
import { useState } from "react";

const useModal = () => {
  let [isShowing, setIsShowing] = useState<Array<any>>([]);

  const handleModal = (action:string, alias: string) => {      
    if (action === 'close') {
        const newIsShowing =  isShowing.filter(
            modal => modal.alias !== alias
        );
        
        setIsShowing(newIsShowing);
    } else {
        setIsShowing([...isShowing, { action: 'open', alias }]);
    }
  };

  return {handleModal, isShowing };
};

export default useModal;
```

#### Context

O Context é responsável por ser um intermediário entre os estados e funções armazenados no useModal com o componentes que deve utilizá-lo.

```javascript
import React, { ContextType, createContext, ReactChild, ReactChildren } from "react";
import useModal from "../hooks/useModal";

interface Props {
    children: ReactChild | ReactChildren;
}
   
export const ModalContext = createContext<any>({});

let ModalProvider = ({ children }: Props) => {

  const { handleModal, isShowing } = useModal();

  return (
    <ModalContext.Provider value={{ handleModal, isShowing }}>
      {children}
    </ModalContext.Provider>
  );
};

export default ModalProvider;
```