On this StackBlitz
: https://stackblitz.com/edit/csstransition-test
I have a project that open a green div with a zoom-in
effect:
/src/App.js
import React, { useState } from 'react';
import './style.css';
import Modal from './Modal';
export default function App() {
const [ isOpen, setIsOpen ] = useState(false);
const handleClick = () => {
setIsOpen(!isOpen);
};
return (
<div>
<h1>Hello StackBlitz!</h1>
<p>Start editing to see some magic happen :)</p>
<button onClick={handleClick}>Click Me</button>
<br /><br />
<Modal isOpen={isOpen}>
<div>Hello World</div>
</Modal>
</div>
);
}
/src/Portal.js
import { Component } from 'react';
import ReactDOM from 'react-dom';
const portal = document.getElementById('portal');
export default class Portal extends Component {
render() {
return ReactDOM.createPortal(this.props.children, portal);
}
}
/src/Modal.jsx
import React, { useRef } from "react";
import { CSSTransition } from "react-transition-group";
import Portal from "./Portal";
export default function Modal({ isOpen, children }) {
const container = useRef(null);
return (
<CSSTransition
nodeRef={container}
in={isOpen}
timeout={300}
classNames="modal"
unmountOnExit
onEnter={ () => console.log('entered') }
onExited={ () => console.log('exited') }
>
<div ref={container} style={{
display: 'inline-block',
backgroundColor: '#0f0',
padding: '50px',
}}>
{children}
</div>
</CSSTransition>
);
}
/src/style.css
h1,
p {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
.modal-enter {
transform: scale(0);
}
.modal-enter-active {
transform: scale(1);
transition: transform 300ms;
}
.modal-exit {
transform: scale(1);
}
.modal-exit-active {
transform: scale(0);
transition: transform 300ms;
}
My problem is: I need to make it work with Portals.
On file: /src/Modal.jsx, if I replace the div
inside: CSSTransition
with: Portal
then I get errors.
This is the code with the change:
/src/Modal.jsx
import React, { useRef } from "react";
import { CSSTransition } from "react-transition-group";
import Portal from "./Portal";
export default function Modal({ isOpen, children }) {
const container = useRef(null);
return (
<CSSTransition
nodeRef={container}
in={isOpen}
timeout={300}
classNames="modal"
unmountOnExit
onEnter={ () => console.log('entered') }
onExited={ () => console.log('exited') }
>
<Portal ref={container} style={{
display: 'inline-block',
backgroundColor: '#0f0',
padding: '50px',
}}>
{children}
</Portal>
</CSSTransition>
);
}
Please try the StackBlitz
: https://stackblitz.com/edit/csstransition-test and you are also welcomed to post your own forked StackBlitz
with the fixes.
Thanks!
I think this is happing because CSSTransition
component is being created in root
element. And the model is created in your portal
element. This CSSTransition component is not wrapping anything.
You should instead wrap the whole Model with the portal, like this:
<Portal>
<CSSTransition
nodeRef={container}
in={isOpen}
timeout={300}
classNames="modal"
unmountOnExit
onEnter={ () => console.log('entered') }
onExited={ () => console.log('exited') }
>
<div ref={container} style={{
display: 'inline-block',
backgroundColor: '#0f0',
padding: '50px',
}}>
{children}
</div>
</CSSTransition>
</Portal>
I hope this helps.