Reputation: 1997
I have a component which renders a react-modal
, my problem is the react-modal
does not open. modalFileNameOpen
useState
property does not set properly.
const [modalFileNameOpen, setmodalFileNameOpen] = useState(false)
const handleFileNameChangeClick = () => {
console.log(modalFileNameOpen) // set to false
setmodalFileNameOpen(true) // this does not set the `modalFileNameOpen` to true.
console.log(modalFileNameOpen) // is still false
}
return (
<div className="container-fluid">
<input type="button" className="btn" onClick={handleFileNameChangeClick} value="Rename File"></input>
<ModalFileName modalFileNameOpen={modalFileNameOpen} />
</div>
)
I have another component ModalFileName
import React, { useState } from 'react';
import Modal from 'react-modal';
Modal.setAppElement('#root');
const ModalFileName = ({ modalFileNameOpen }) => {
const [modalIsOpen, setModalIsOpen] = useState(modalFileNameOpen)
return (
<Modal isOpen={modalIsOpen} onRequestClose={() => setModalIsOpen(false)}>
<div>
<h1>File Name Change</h1>
<div>
<button onClick={() => setModalIsOpen(false)}>Close</button>
</div>
</div>
</Modal>
)
}
export default ModalFileName;
Upvotes: 1
Views: 5588
Reputation: 12911
Here is a minimal example of what you seem to be trying to achieve.
It is a basic illustration of pulling state up to the parent and passing a handler function down to the child. In your code you were attempting to do this by declaring a new state in the child based on the parent's state which leads to unnecessary duplication and possible state conflicts down the road.
We declare our modal state and setter and a basic handler function:
const [openModal, setOpenModal] = useState(false);
const toggleModal = () => {
setOpenModal(!openModal);
}
We then conditionally render our modal component based on the current state value. If openModal
is false we render the button to open it, otherwise we render the Modal component and pass our handler function toggleModal
to it as a prop.
// if openModal is false render the button, else render our modal
{!openModal ?
<button type="button" onClick={toggleModal}>Open Modal</button>
: <Modal handler={toggleModal} />
}
If the modal is rendered it recieves the handler (here retrieved through destructuring function Modal({handler}) {...
) and assign it to the onClick
of the close button on our modal.
function Modal({handler}) {
return (
<div className="modal" >
<p>I'm a modal</p>
<button type="button" onClick={handler}>Close Modal</button>
</div>
)
}
Working Example
body {
padding: 0;
margin: 0;
}
.container {
position: relative;
height: 100vh;
width: 100vw;
background: gray;
}
.modal {
height: 50vh;
width: 50vw;
position: absolute;
top: 25%;
left: 50%;
transform: translateX(-50%);
background-color: aqua;
}
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<div id="App"></div>
<script type="text/babel">
const {useState} = React;
function App() {
const [openModal, setOpenModal] = useState(false);
const toggleModal = () => {
setOpenModal(!openModal);
}
return (
<div className="container">
{!openModal ?
<button type="button" onClick={toggleModal}>Open Modal</button>
: <Modal handler={toggleModal} />
}
</div>
)
}
function Modal({handler}) {
return (
<div className="modal" >
<p>I'm a modal</p>
<button type="button" onClick={handler}>Close Modal</button>
</div>
)
}
ReactDOM.render(<App />, document.getElementById('App'));
</script>
Some notes
If you console.log()
before and after the setOpenModal()
call you will get the same results that you did in your question; it will print the same value that it entered the render with. If it doesn't there is a problem and you have mutated the state. From the Docs
Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.
const [openModal, setOpenModal] = useState(false);
const toggleModal = () => {
console.log(openModal); // prints the value of openModal on entering render
setOpenModal(!openModal); // sets openModal to !openModal
console.log(openModal); // prints the value of openModal on entering render
}
Also, you may want to pass arguments to your passed handler (arguably the close
button should always set openModal
to false
rather than hoping that toggling it will close it).
To do this you can simply accept an argument in your handler function.
const toggleModal = (newState) => {
setOpenModal(newState);
}
and pass it in your onClick
calls.
<button type="button" onClick={() => toggleModal(true)}>Open Modal</button>
function Modal({handler}) {
return (
<div className="modal" >
<p>I'm a modal</p>
<button type="button" onClick={() => handler(false)}>Close Modal</button>
</div>
)
}
Upvotes: 1