ReactJs Pass State from Navbar to child components - reactjs

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>
</>
}
)
}

Related

How to call an individual modal box component in react?

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.

React-Bootstrap input text lose focus when opened from a OverlayTrigger in a Modal

I have a button in a modal that on click opens a popover component, in the popover I have an input text field.
The problem I have is that the input lose focus instantly, I can't type in it because something else is hijacking the focus out of it and I can't figure out what is, here is a working example of the problem.
And here is the code in question:
import "./styles.css";
import { Fragment, useState } from "react";
import { Button, Modal, OverlayTrigger, Popover, Form } from "react-bootstrap";
export default function App() {
const [showModal, setShowModal] = useState(false);
const [inputValue, setInputValue] = useState("");
const popover = (
<Popover id="popover-basic">
<Popover.Content>
<Form.Control
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="Enter value"
/>
</Popover.Content>
</Popover>
);
return (
<div className="App">
<Fragment>
<Button variant="primary" onClick={() => setShowModal(true)}>
Open
</Button>
{showModal && (
<Modal
show={showModal}
onHide={() => setShowModal(false)}
centered
backdrop="static"
animation={false}
>
<Modal.Header closeButton>modal</Modal.Header>
<Modal.Body>
<p>Hello</p>
<OverlayTrigger
trigger="click"
placement="right"
overlay={popover}
>
<Button variant="secondary">Open Popover</Button>
</OverlayTrigger>
</Modal.Body>
</Modal>
)}
</Fragment>
</div>
);
}
Modal has a property "enforceFocus", which keeps focus on the Modal component. The property value is set to true per default. Set it to false and you will be able to use your input.
"https://react-bootstrap-v4.netlify.app/components/modal/#modal-props
Disabling the enforceFocus works, but I'm not sure it is the best alternative. If the user navigates the fields using the tab key, he might focus elements outside of the modal, which could create confusion.
Instead, I suggest you play with the overlay's container prop. You could use a ref to the modal itself, or to a container inside the modal. This way, the overlay will be "inside" the modal and won't lose focus.
I created an example to demonstrate it works.

React set multiple states on an event

I have a modal that when it is closed updates a state. The modal also has a div which will be replaced if a button is clicked. The button is replaced with a text area and 2 buttons (one of them a cancel.) If the cancel is clicked, the state updates and the text area hides. All good. However, if the user closes the modal, then the state is not updated and the div is shown next time.
I am unsure of how to set 2 states on close for the modal, I think this could sort this issue.
Code has been updated as per #jsNoob suggestion:
Hint component has
const [showModalProblemS_vid, setShowModalProblemS_vid] = useState(false);
<VideoModal showModal={showModalProblemS_vid} closeHandler={() => setShowModalProblemS_vid(false)} videoMessage={props.prob_s_vid} size='med'/>
So how to set a state which is not in the file is the issue
Modal Code below:
import Button from 'react-bootstrap/Button';
import Modal from 'react-bootstrap/Modal';
import { useState } from 'react';
function VideoModal({showModal = false, closeHandler = () =>{}, videoMessage, content, size}) {
const [confused, setConfused] = useState(false)
return (
<Modal
size={size}
show={showModal}
onHide={closeHandler}
onClose={()=> {setConfused(false); closeHandler()}}
backdrop="static"
keyboard={false}
>
<Modal.Body>
<video src={videoMessage} controls autoPlay></video>
<div>
{confused ? (
<div>
What have you found confusing about this video?
<textarea className='confusedText' rows="2"></textarea>
<Button className="confusedBtnSave">
Save
</Button>
<Button className="confusedBtnCancel" onClick={()=>setConfused(false)}>
Cancel
</Button>
</div>
) : (
<div>
<Button className="confusedBtn" onClick={()=>setConfused(true)}>
Confused?
</Button>
</div>
)}
</div>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={closeHandler}>
Close
</Button>
</Modal.Footer>
</Modal>
)
}
export default VideoModal
Well to set multiple states you can do that inline
<Button onClick={() => {setState1(foo); setState2(bar)}}></Button
Or you could add them to a function and then call the function inline
function multipleStates(foo, bar){
setState1(foo)
setState2(bar)
}
<Button onClick={() => multipleState(foo, bar)}></Button>
I'm not sure if that is too broad of an answer for you, hopefully I haven't misinterpreted your question.
Got this working. I had to use the following:
onClick={() => {onClose(); setConfused(false)}}
note the semi-colon between the states

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.

use same function for different buttons

I have created a button at the bottom of the page which when clicked open a modal.
Now I have a button in a header. I want that when we click on that header button it should too open the modal. That is how can we use the same function which is used for the button which is at the bottom of the page.
Button clicks should set state. State decides if modal is shown
One way of doing it with hooks is having the buttons set state with a boolean value that decides if the modal is shown.
const Component = () => {
const [modalOpen,setModalOpen] = useState(false)
return (
<div>
<button onClick={setModalOpen(true)} >
Open Modal 1
</button>
<div>
Your other content
</div>
<button onClick={setModalOpen(true)} >
Open Modal 2
</button>
<Modal show={modalOpen} />
</div>
)
}

Resources