React set multiple states on an event - reactjs

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

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

mui Dialog not closing properly

I have a problem with a dialog not closing properly.
Dialog open is set to a state variable intialized as true, and immediately changed to false.
The dialog doesn't close properly, and the app does not respond.
I have demonstrated this in the following sandbox where the button can not be clicked, though it should be available.
EDIT:
To make clear. The dialog is not supposed to ever open. But the button outside the dialog (with the text "a button") should be clickable.
https://codesandbox.io/s/adoring-benji-300mcm
This code will work:
export default function App() {
const [open, setOpen] = useState(false);
console.log(open);
return (
<div>
<Dialog open={open} height="100px" width="100px" id="111">
<button onClick={() => setOpen(false)}>close</button>
</Dialog>
<button onClick={() => console.log("click")}>a button</button>
</div>
);
}
You don't need the useEffect to change state immediately, you could just pass false as a desired initial value to the state. Now the button "a button" is working.
EDIT:
To make the code working without removing useEffect, add conditional rendering:
export default function App() {
const [open, setOpen] = useState(true);
useEffect(() => setOpen(false), []);
console.log(open);
return (
<div>
{open && (
<Dialog open={open} height="100px" width="100px" id="111">
<button onClick={() => setOpen(false)}>close</button>
</Dialog>
)}
<button onClick={() => console.log("click")}>a button</button>
</div>
);
}
My best guess is that in your code the Dialogue gets rendered anyways, even though it is not displayed, because at first "open" was true. So in order for it not to be rendered, or to be rendered conditionally, you should check state.

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.

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

Resources