Refactor with-modal example (#9097)

## Changelog

- Use functional components instead of class components
- Use default exports like in all other examples
- Rename `Portal` component to `ClientOnlyPortal`.
This commit is contained in:
Henrik Wenz 2019-10-18 07:50:10 +02:00 committed by Joe Haddad
parent c650ed9a2a
commit 2874a3e0f1
5 changed files with 69 additions and 85 deletions

View file

@ -0,0 +1,14 @@
import { useRef, useEffect, useState } from 'react'
import { createPortal } from 'react-dom'
export default function ClientOnlyPortal ({ children, selector }) {
const ref = useRef()
const [mounted, setMounted] = useState(false)
useEffect(() => {
ref.current = document.querySelector(selector)
setMounted(true)
}, [])
return mounted ? createPortal(children, ref.current) : null
}

View file

@ -1,68 +1,56 @@
import * as React from 'react'
import React, { useState } from 'react'
import ClientOnlyPortal from './ClientOnlyPortal'
import { Portal } from './Portal'
export default function Modal () {
const [open, setOpen] = useState()
export class Modal extends React.Component {
constructor () {
super(...arguments)
this.state = { opened: false }
}
open = () => {
this.setState({ opened: true })
}
close = () => {
this.setState({ opened: false })
}
render () {
return (
<React.Fragment>
<button type='button' onClick={this.open}>
Open Modal
</button>
{this.state.opened && (
<Portal selector='#modal'>
<div className='overlay'>
<div className='modal'>
<p>
This modal is rendered using{' '}
<a href='https://reactjs.org/docs/portals.html'>portals</a>.
</p>
<button type='button' onClick={this.close}>
Close Modal
</button>
</div>
<style jsx global>{`
body {
overflow: hidden;
}
`}</style>
<style jsx>{`
.overlay {
position: fixed;
background-color: rgba(0, 0, 0, 0.7);
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.modal {
background-color: white;
position: absolute;
top: 10%;
right: 10%;
bottom: 10%;
left: 10%;
padding: 1em;
}
`}</style>
return (
<React.Fragment>
<button type='button' onClick={event => setOpen(true)}>
Open Modal
</button>
{open && (
<ClientOnlyPortal selector='#modal'>
<div className='backdrop'>
<div className='modal'>
<p>
This modal is rendered using{' '}
<a href='https://reactjs.org/docs/portals.html' target='_blank'>
portals
</a>
.
</p>
<button type='button' onClick={event => setOpen(false)}>
Close Modal
</button>
</div>
</Portal>
)}
</React.Fragment>
)
}
<style jsx>{`
:global(body) {
overflow: hidden;
}
.backdrop {
position: fixed;
background-color: rgba(0, 0, 0, 0.7);
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.modal {
background-color: white;
position: absolute;
top: 10%;
right: 10%;
bottom: 10%;
left: 10%;
padding: 1em;
}
`}</style>
</div>
</ClientOnlyPortal>
)}
</React.Fragment>
)
}

View file

@ -1,17 +0,0 @@
import React from 'react'
import ReactDOM from 'react-dom'
export class Portal extends React.Component {
componentDidMount () {
this.element = document.querySelector(this.props.selector)
this.forceUpdate()
}
render () {
if (this.element === undefined) {
return null
}
return ReactDOM.createPortal(this.props.children, this.element)
}
}

View file

@ -7,7 +7,7 @@ export default class extends Document {
<Head />
<body>
<Main />
{/* here we will mount our modal portal */}
{/* Here we will mount our modal portal */}
<div id='modal' />
<NextScript />
</body>

View file

@ -1,5 +1,4 @@
import * as React from 'react'
import { Modal } from '../components/Modal'
import React from 'react'
import Modal from '../components/Modal'
export default () => <Modal />