How to call an individual modal box component in react? - reactjs

I wanted to open/load a react bootstrap model box component (Modalbox.js) to App.js, but the modal box open button code in App.js, how to do that? please help.
In App.js, there will be multiple buttons for call multiple type modalboxs. modalbox.js should contain only modal box code. modal launch buttons should be in App.js
<button variant="primary" onClick={handleShow}>Launch demo modal</button>
https://codesandbox.io/s/individual-modal-box-component-ti6ugg

I have added only functionality on the show and hide here is code so that you may get the idea props and manage the state accordingly all remaining code it feels free to add more functionality and custome state
import "./styles.css";
import Modalbox from "./Modalbox";
import { useState } from "react";
export default function App() {
const[handleShow,sethandleShow] = useState(false)
return (
<div className="App">
<button variant="primary" onClick={()=>sethandleShow(!handleShow)}>
Launch demo modal
</button>
<Modalbox handleShow={handleShow} sethandleShow={sethandleShow} />
</div>
);
}
modalbox.js
import React, { useState } from "react";
import { Modal, Button } from "react-bootstrap";
function Modalbox(props) {
const [modalshow, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
return (
<div>
{/* <Modal show={modalshow} onHide={handleClose}> */}
<Modal show={props.handleShow} onHide={()=>props.sethandleShow(!props.handleShow)}>
<Modal.Header closeButton>
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>Woohoo, you're reading this text in a modal!</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={()=>props.sethandleShow(!props.handleShow)}>
Close
</Button>
<Button variant="primary" onClick={handleClose}>
Save Changes
</Button>
</Modal.Footer>
</Modal>
</div>
);
}
export default Modalbox;

You should create a state in App.js called "showModal" which is a boolean. Pass that state as props to Modal. also in your handleshow function you should setState based on the prevState like so: setShowModal((prevState)=> !prevState). In your modal component you should use the showModal prop you passed but remember never use props as the defaut value in useStates.

You put the state for showing the Modalbox in it, but it doesn't know from outside when to show. I'm afraid you have to at least put the show state in App.js. The rest of the logic can remain in Modalbox.js.
I forked your condesandbox:
https://codesandbox.io/s/individual-modal-box-component-forked-moy9ok
The other possibility is to use the Context API and maybe write a hook for it. Then you wouldn't need to directly pass the state down to Modalbox. But it's not really a suitable use case for the Context API. It's rather for prop drilling.

Related

ReactJs Pass State from Navbar to child components

Greetings and thank you for stopping by to check this. I'm having some issues and I don't reall know how to fix this.
I have a react js app acctually running with nextjs. So the thing is, I have a navbar, as a compoents and a sign up page as a component.
What I want is simple, when I click on the sign up button on the navbar, the signUp modal should pop up, and when I click on the close (x) icon on the modal, the modal should close.
So far, I've made it possible with useState to show the signUp modal when the signUp button is clicked.
Since the signUp modal is a component that I'm importing to the navabr, I'm finding it difficult to useState to close it when opened.
This is my code.
import SignUpModal from '../SignIn/Register';
function Navbar(
// Show Reigster Modal when the button is clicked
const [register, setRegister] = useState(false);
return () {
<>
{register ? <SignUpModal /> : ''}
<nav>
<div>
<Link>Home</Link>
<Link>About</Link>
<Link>Login</Link>
<button
type="button"
onClick={() => setRegister(!register)} > Sign Up
</button>
</div>
</nav>
</>
)
}
Now, when I click on the signUp button, the modal that I imported, is shown. But on the modal components, I can't close the modal because I can't pass the state from the navbar to the SignUp compoents and close it when I click on the close(x) icon.
On the SignUp component, I know I can do <button type="button" onClick={() => setNavbar(!navbar)}>Close</button>
But how do I pass it? Please someone should help me, thanks!
`
For closing the modal from within the modal component, you just need to pass in a function as a prop to the component, which you can call within the onClick() function of the close button.
import SignUpModal from '../SignIn/Register';
function Navbar(
// Show Reigster Modal when the button is clicked
const [register, setRegister] = useState(false);
return () {
<>
{register && <SignUpModal onClose={() => setRegister(false)} />}
<nav>
<div>
<Link>Home</Link>
<Link>About</Link>
<Link>Login</Link>
<button
type="button"
onClick={() => setRegister(true)} > Sign Up
</button>
</div>
</nav>
</>
}
)
}

Error: Invalid hook call - when calling a Modal component

When I try to call the Modal component I'm getting this error -
Error: Invalid hook call. Hooks can only be called inside of the body
of a function component. This could happen for one of the following
reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app See https://reactjs.org/link/invalid-hook-call for tips about how to debug
and fix this problem.
How can I show this modal when pressing a button in functional component?
Thanks
Search.jsx
import AddedToCart from '../modals/Modal';
const Search=()=>{
return(
<div>
<button
onClick={() => AddedToCart()}
>
</div>
)
}
Modal.jsx
import Modal from 'react-bootstrap/Modal';
import React, { useState } from 'react';
export default function AddedToCart() {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
return (
<>
<button variant='primary' onClick={handleShow}>
Launch demo modal
</button>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>Woohoo, you're reading this text in a modal!</Modal.Body>
<Modal.Footer>
<button variant='secondary' onClick={handleClose}>
Close
</button>
<button variant='primary' onClick={handleClose}>
Save Changes
</button>
</Modal.Footer>
</Modal>
</>
);
}
Any help will be awesome.
onClick={() => AddedToCart()}
You are calling it like a function in a click handler, that is not how you render stuff in react.
instead set a flag
onClick={() => setOpenModal(true)}
and then in render
{openModal && <AddedToCart/>}

React JS - Reset Form Data after Modal Close

I'm trying to reset my form data when a modal closes. I think part of my problem is that the form data <Mint> is in another component.
Honestly, any time the modal is shown or hidden I would like to reset the data.
So if there is a way I can reset the form data inside the toggleModalOne() function that would be awesome, but I can't figure out how.
Any advice is greatly appreciated.
// BuyIt.jsx
import React, { useState } from "react";
import TextLoop from "react-text-loop";
import Modal from "react-modal";
import Mint from "../../components/slider/mint.js";
const BuyIt = () => {
const [isOpen, setIsOpen] = useState(false);
function toggleModalOne() {
setIsOpen(!isOpen);
}
return (
<div className="div-buyNowBtn">
<button id="buyNowBtn" className="white-fill-bg btn-outline btn-lg" onClick={toggleModalOne}>
Buy Now
</button>
</div>
<Modal
isOpen={isOpen}
onRequestClose={toggleModalOne}
contentLabel="My dialog"
className="custom-modal"
overlayClassName="custom-overlay"
closeTimeoutMS={500}
>
<Mint/>
</Modal>
);
}
You could wrap your Modal around a check to see if isOpen is true. This will make the whole modal re-render each time rather than just hiding and showing it but it still being in the DOM (which is what I am assuming is happening).
{ isOpen &&
<Modal
isOpen={isOpen}
onRequestClose={toggleModalOne}
contentLabel="My dialog"
className="custom-modal"
overlayClassName="custom-overlay"
closeTimeoutMS={500}
>
<Mint></Mint>
</Modal>
}
If you want a parent function to reset a child's form state, you probably will want to lift the state up to the parent and pass it down as a prop.

React bootstrap modal not opening when onHide function is enabled

I am noticing that my React Bootstrap modal wont open when I put the following condition : onHide={props.setShowModal(false)}. When I change it to onHide={props.setShowModal(true)} then it always stays open.
What is going wrong ?
PARENT JS --------
const [showModal, setShowModal] = useState(false);
<AddModal showModal={showModal} setShowModal={setShowModal} />
MODAL -------
import React, { useState, useEffect } from 'react';
import { Button, Form, FormControl, Modal } from "react-bootstrap";
const AddModal = (props) => {
const handleClose = () => {
props.setShowModal(false);
}
return (
<Modal show={props.showModal} animation={false}
// onHide={props.setShowModal(false)}
>
<Modal.Header closeButton>
<Modal.Title>Enter Item</Modal.Title>
</Modal.Header>
{
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}
>
Cancel
</Button>
<Button variant="primary" onClick={handleClose}
>
Save Changes
</Button>
</Modal.Footer>}
</Modal>
);
}
export default AddModal;
This happens because props.setShowModal(false) is immideatly called when your modal is rendered. You can fix it by changing your code to onHide={() => props.setShowModal(false)}.
This is a common trap. onHide (as well as onClick and any other event handlers) expects a function that will be called when event is fired. props.setShowModal is a function, props.setShowModal(false) is not. So your options are either pass a lamda function as I suggested, or create a function
hideModal() {
props.setShowModal(false)
}
and pass it to onHide.

Reusable Modal Component React Typescript

I have a component which has a button within it, like so -
<Button variant="primary" disabled={checkAccepted} onClick={openModal}>Send</Button>
I would like this button to, when it is active, to open up a modal when clicked. I am unsure how to do this and have been messing around with props but can't seem to figure it out. I also want the modal to be reusable so that any content can be passed in the modal body.I am thinking how do I open up the modal from within my openModal function?
I tried returning it like so -
const openModal = () => {
return (
<Modal>
<ModalBody>*Pass in swappable content here*</ModalBody>
</Modal>
)
}
But that doesn't seem to work. I am sure I am missing something.
You can't return components from an event handler. The way to handle events in react is almost always to alter the state of your application which triggers a re-render. In your case you need to keep track of the open state of your modal.
This can be done either in a controlled way (you keep track of the open state yourself and pass it to your <Modal> component as a prop) or in an uncontrolled way (the <Modal> component manages the open state itself). The second approach requires that you provide e.g. an element to render to your Modal component that acts as a trigger:
const MyModal = ({ children, trigger }) => {
const [modal, setModal] = useState(false);
const toggle = () => setModal(!modal);
return (
<div>
{React.cloneElement(trigger, { onClick: toggle })}
<Modal isOpen={modal} toggle={toggle}>
<ModalBody>{children}</ModalBody>
</Modal>
</div>
);
};
Then you can use it like that:
<MyModal trigger={<Button variant="primary">Send</Button>}>
<p>This is the content.</p>
</MyModal>
Or you can implement it in a controlled way. This is more flexible as it allows you to render the triggering element anywhere:
const MyModal = ({ children, isOpen, toggle }) => (
<div>
<Modal isOpen={isOpen} toggle={toggle}>
<ModalBody>{children}</ModalBody>
</Modal>
</div>
);
Usage Example:
function App() {
const [isOpen, setIsOpen] = useState(false);
const toggle = () => setIsOpen(!isOpen);
return (
<div className="App">
<Button variant="primary" onClick={toggle}>
Send
</Button>
<MyModal isOpen={isOpen} toggle={toggle}>
<p>This is the content.</p>
</MyModal>
</div>
);
}
You should pass the function which triggers the modal to your <Button /> component as prop. Then, in your component, you want to add the onClick event. You can't set an onClick event to the <Button />. It will think of onClick as a prop being passed to <Button />. Within <Button /> you can set the onClick event to an actual <button> element, and use the function which was passed in as a prop on that event.
You can use state to keep track of when the modal button is clicked. Your function can look like: (I am using class based components here, but you can do the same thing with functional components)
buttonClickedHandler = () => {
this.setState({isModalButtonClicked: !this.state.isModalButtonClicked});
}
Then, you can set the Modal component,
<Modal isShow={this.state.isModalButtonClicked} modalButton={this.buttonClickedHandler}>
<div> ...set contents of modal</div>
</Modal>
<button onClick={this.buttonClickedHandler}>Show Modal</button>
So, within the Modal component, you can have something like this:
<React.Fragment>
<Backdrop showModal={this.props.isShow} clicked={this.props.modalButton}/>
{this.props.children}
</React.Fragment>
Backdrop is basically the greyed out background. You can also set an onClick event to listen to when the backdrop is clicked.

Resources