So basically I'm trying to tie in the Login and Sign Up component to the Main component by making use of onClick action of a button.
Given below is the code segment
function Dev({value}){
const [isButton, ButtonClicked ] = useState(false);
const handleClick=()=> ButtonClicked(!isButton);
return(
<div>
<Card>
<CardImg top width="100%" src={value.src} alt="Card image cap" />
<CardBody>
<CardTitle className='text-card'>{value.title}</CardTitle>
<CardText className='text-text'>{value.text}</CardText>
<Button className='text-button' onClick={handleClick}>{value.button}<i class={value.icon} aria-hidden="true"></i></Button>
</CardBody>
</Card>
{isButton && (value.id ? <Login open={true} /> : <Sign open={true}/>)}
</div>
);
}
The code works fine, but there is an issue.
When I first click on the button, isButton will be set to true and the Login component will pop up. After closing it, I have to click twice on the button to render the Login component again.
I know the reason behind this; when I click on the button the second time isButton will be toggled to false and I should click again to toggle it to true. This is kind of inappropriate, is there any way to work around this issue?
The code for Login Component
const Login = (props) => {
const [modal, setModal] = useState(props.open);
const toggle = () => setModal(!modal);
return (
<div>
<Modal isOpen={modal} toggle={toggle}>
<ModalHeader toggle={toggle}>Login</ModalHeader>
<ModalBody>
.
.
.
</ModalBody>
</Modal>
</div>
);
}
export default Login;
Related
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.
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.
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
Let's say I have a button that opens a Dialog component. The button has custom theming/styling to specify various states, one of them being the :focus state:
const useStyles = makeStyles({
root: {
"&:focus": {
backgroundColor: "#3A7DA9"
}
}
});
export default function App() {
const [open, setOpen] = useState(false);
const classes = useStyles();
return (
<div className="App">
<Button
id="button-that-opens-modal"
className={classes.root}
onClick={() => setOpen(true)}
>
Open the modal
</Button>
<Dialog open={open}>
<h3>This is the modal</h3>
<Button onClick={() => setOpen(false)}>
Close
</Button>
</Dialog>
</div>
);
}
What I've noticed is that every time I have this pattern, (where a button opens a dialog modal), when the modal is closed, the #button-that-opens-modal is left with a :focus state, which looks bad in terms of styling. Here's a quick gif:
Codesandbox demonstrating the issue
Is this a known issue? I don't see why the :focus should be automatically applied to the button when the modal closes. How can I stop this?
I tried this:
I can add a ref to the button, and make sure to manually unfocus the button in various places. Adding it in the onExited method of the Dialog works, but flashes the focus state for a second:
export default function App() {
const [open, setOpen] = useState(false);
const buttonRef = useRef();
const classes = useStyles();
return (
<div className="App">
<Button
ref={buttonRef}
className={classes.root}
onClick={() => setOpen(true)}
>
Open the modal
</Button>
<Dialog
open={open}
TransitionProps={{
onExited: () => {
buttonRef.current?.blur(); // helps but creates a flash
}
}}
>
<h3>This is the modal</h3>
<Button onClick={() => {setOpen(false)}}>
Close
</Button>
</Dialog>
</div>
);
}
sandbox showing this very imperfect solution
And even if I found exactly the right event handler to blur the button such the styling looks correct, this is not something I want to do for every Dialog in an app that has many Button - Dialog pairs. Is there a Material-UI prop I can use to disable this 'auto-focus' back on the button, rather than having to create a ref and manually .blur it for every Dialog?
This is for accessibilty purpose. You can disable it by adding prop disableRestoreFocus on your Dialog :)
I am using the Ant Design components for some interfaces in a React App but I'm noticing an issue with Modals and Tooltips. Usually when the modal is empty or is simple - e.g has only a text it is going to show properly but in case there are more elements on it (on production scenario) it flickers.
You can visually watch the flickering issue here: https://drive.google.com/file/d/1ODsj-aGz6saHJLXLI7sJaesgHKKPrvD2/view
Hope to get some answers :-) Thank you!
The visibleRequest state variable is triggered true by a button in the interface.
EDIT: As requested here's my code:
renderRequests=()=>{
const data = [
{name:"Request #1",description:"Request description",status:"0"},
{name:"Request #1",description:"Request description",status:"1"},
{name:"Request #1",description:"Request description",status:"2"}
];
const handleOk = ()=>{
console.log("Submitted");
this.setState({visibleRequest:false})
}
const handleCancel = ()=>{
this.setState({visibleRequest:false})
}
return(
<div style={{overflowY:"scroll"}}>
<Modal
title="Submit new request"
visible={this.state.visibleRequest}
onOk={handleOk}
onCancel={handleCancel}
>
<Input placeholder="Title"/>
<Input.TextArea placeholder="Description"/>
<DatePicker/>
</Modal>
<List
dataSource={data}
renderItem={item=>{
return(
<List.Item>
<List.Item.Meta
title={item.name}
description={item.description}
/>
{item.status==1?<Tooltip title="Request approved">
<Icon type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
</Tooltip>:
item.status==2?<Icon type="close-circle" theme="twoTone" twoToneColor="#7F1C43" />:<Icon type="ellipsis" theme="outlined" />}
</List.Item>
)
}}/>
<Pagination total={20}/>
</div>
)
}