Looking for suggestions for a better solution - reactjs

So I have a site which has 12 buttons. 6 of these buttons will need to launch a popup with a different video and 6 buttons will need to launch a popup with 6 images.
Now, currently, I am experimenting with a single popup displaying an image. And this is fairly easy, I set a state
const [showModal, setShowModal] = useState(false);
And then I have a button which will set the show onClick and then a model is shown - eg
<button className="buttonGeneral" onClick={()=>setShowModal(true)}>SUMMARY11</button> <ModalReact showModal={showModal} onClose={() => setShowModal(false)} image={props.image_1} size='med'/>
Thinking about this, I am thinking I will need 2 different types of modals, one for video and one for images. But with the approach above, I am going to need to useState with 12 different states. This seems a bit wrong, but I cannot think of any other way.
For completeness, here is the ModalReact component
import Button from 'react-bootstrap/Button';
import Modal from 'react-bootstrap/Modal';
import '../styles/react-bs.css';
function ModalReact({showModal = false, onClose = () =>{}, image, size}) {
console.log("im ", image)
return (
<Modal
size={size}
show={showModal}
onHide={onClose}
backdrop="static"
keyboard={false}
// dialogClassName="videoPopup"
>
<Modal.Body><img src={image} alt="lala"></img></Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={onClose}>
Close
</Button>
</Modal.Footer>
</Modal>
)
}
export default ModalReact

You need to maintain different states for all the buttons. I would suggest writing a custom component with its state maintained in the same component so that it's available for only that component. Based on that, we can open a modal from its state variable.
export default function ModalReact({ itemNum }) {
const [showModal, setShowModal] = useState(false);
const handleClose = () => setShowModal(false);
const handleShow = () => setShowModal(true);
return (
<>
<Button variant="primary" onClick={handleShow}>
Launch demo modal {itemNum}
</Button>
<div style={{ display: "block", width: 700, padding: 30 }}>
<Modal show={showModal} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Modal heading {itemNum}</Modal.Title>
</Modal.Header>
<Modal.Body>
Woohoo, you're reading this text in a modal! {itemNum}
{itemNum > 6 ? "image" : "video"}
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
<Button variant="primary" onClick={handleClose}>
Save Changes
</Button>
</Modal.Footer>
</Modal>
</div>
</>
);
}
We can use that from any component. You said you have 12 buttons so iterate and display all those buttons. I have used a simple array and iterating to display all the buttons.
return (
<div className="container">
{Array.from({ length: 12 }, (_, i) => i + 1).map((item) => (
<CustomModal itemNum={item} />
))}
</div>
);
Attached is a sandbox for reference.

Related

React + Bootstrap modal questions

I am trying to put a modal dialog using react-bootstrap and having issues.
I have a "HintComponent" which consists of a bunch of buttons
<div className="col-5 d-grid gap-2 borderGeneral">
<button className="buttonGeneral" >Label here</button>
<button className="buttonGeneral">SUMMARY</button>
</div>
and I want to launch a Modal dialog on clicking a button.
Looking at the react-bootstrap site, I have the following (taken straight from the site)
import React, {useState} from 'react';
import Button from 'react-bootstrap/Button';
import Modal from 'react-bootstrap/Modal';
import render from 'react-dom';
function Example() {
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>
</>
);
}
render(<Example />);
My issue is - how do I call the Modal from the HintComponent? If I try to import the Modal (in this case ) and call it as just I get a warning about module having no exports.
Can anyone give me a hint?
Hi very simple you need to use this component in your HintComponent and pass a prop showModal={true} but before this, you need to receive that prop in your modal component and set it in state using React.useEffect
So your final code will be like below:
ModalComponent
import React, {useState} from 'react';
import Button from 'react-bootstrap/Button';
import Modal from 'react-bootstrap/Modal';
import render from 'react-dom';
function Example(props) {
const {showModal = false, onClose = ()=>{}} = props;
const [show, setShow] = useState(showModal);
React.useEffect(()=>{
setShow(showModal);
},[showModal]);
const handleClose = () => {
setShow(false);
// just to have custom function for modal close which will be used can be used in HintComponent maybe you want to perform somehting else after modal close.
typeof onClose === 'function' && onClose();
};
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>
</>
);
}
render(<Example />);
I would recommend do not manage Modal visibility in its component but control it from the parent component in your case HintComponent.

How to close Modal in Reactjs?

On button click i was trying to open a model (and modal opening too) and in a same modal it contain a button and on button click i was trying to open another model (and second modal opening too), but when second modal is opening i want first model to be closed. can it be possible?
Here is my sandbox demo https://codesandbox.io/embed/dreamy-herschel-cyetn?fontsize=14&hidenavigation=1&theme=dark
const Practice = () => {
const [modalShow, setModalShow] = useState(false);
const handleSubmit = event => {
setModalShow(true);
};
return (
<div>
<Button onSubmit={handleSubmit} type="submit">
Submit
</Button>
<Modals show={modalShow} onhide={() => setModalShow(false)} />
</div>
);
};
here is my modal part
const Modals = ({ show, onhide }) => {
const [modalShowsec, setModalShowsec] = useState(false);
const Validation = () => {
setModalShowsec(true);
};
return (
<div>
<Modal show={show} onHide={onhide} size="sm" aria-labelledby="contained-modal-title-vcenter" centered>
<Modal.Header closeButton>
<Modal.Title id="contained-modal-title-vcenter">HELLO</Modal.Title>
</Modal.Header>
<Modal.Body>
<p>Hi</p>
</Modal.Body>
</Modal>
<button onClick={Validation}> Validate </button>
<Modal show={modalShowsec} onHide={() => setModalShowsec(false)}>
<Modal.Header closeButton />
<Modal.Body>
<p>Hi cool</p>
</Modal.Body>
</Modal>
</div>
);
};
Call onhide inside Validation function. This will hide the first modal.
const Validation = () => {
setModalShowsec(true)
onhide()
}

Passing props of click event inside new component

When I use standard button with onClick props event it works perfectly fine
<Button onClick={handleClose}>
Agree
</Button>
But I have also created my new component called ButtonSave and onClick is not working
<ButtonSave text="Agree" onClick={handleClose} />
My code inside ButtonSave component
export default function IconLabelButtons(props) {
const classes = useStyles();
return (
<div>
<Button
variant="contained"
color="primary"
size={props.size}
className={classes.button}
startIcon={<SaveIcon />}
>
{props.text}
</Button>
</div>
);
}
How am I supposed to use my handleClose right there?
You need to update your ButtonSave component and pass the onClick prop to it like:
export default function IconLabelButtons(props) {
const classes = useStyles();
return (
<div>
<Button
variant="contained"
color="primary"
size={props.size}
className={classes.button}
startIcon={<SaveIcon />}
onClick={props.onClick}
>
{props.text}
</Button>
</div>
);
}
Hope it works for you.
You need to use onClick which provided in props:
// <ButtonSave text="Agree" onClick={handleClose} />
const ButtonSave = ({ onClick, text }) => (
<Button onClick={onClick}>{text}</Button>
)
Based on the code you provided, it may be because you didn't pass it from ButtonSave to its child of Button. So:
export default function(props) {
return (
<Button onClick={props.handleClose} />
);
}

Why are my variables empty on first click Apollo Client React?

I am trying to call useMutation when I click on the "Save" button on a modal. However, the first time I click it, the variables which get sent are empty (i can see the variables in the network calls tab and all are undefined) even though when I do a console.log I can see the data.
I.e
let globalState = {};
const SessionAdd = () => {
console.log(globalState); // This always displays the correct data when I click on the "Save" button.
const [AddsessionInput, {error} ] = useMutation(addSession,{
variables: {
title:String(globalState.title),
description:String(globalState.description)
}
});
return (
<div className="AddSession">
<Button variant="primary" onClick={handleShow}>
<i className='fas fa-plus' /> Create a new Session
</Button>
<Modal show={show} onHide={handleClose} size="md">
<Modal.Header closeButton>
<Modal.Title><i className='fas fa-camera' /> Create details</Modal.Title>
</Modal.Header>
<Modal.Body> <AddSessionForm /> </Modal.Body>
<Button variant="primary" onClick={AddsessionInput}>
Save
</Button>
</Modal.Footer>
</Modal>
</div>
);
}
const AddSessionForm = () =>{
const [sessionDetails, setSessionDetails] = useState({
title:""
});
const handleSessionDetails = (evt) => {
sessionDetails[evt.target.name] = evt.target.value;
setSessionDetails(sessionDetails);
globalState = sessionDetails;
};
return(
<div>
<p><strong>Add title</strong></p>
<FormControl name="title"
onChange={handleSessionDetails}/>
<br/>
);
}
Is this the correct way to handle states when dealing with a parent component (i.e handling objects in child components from parent state)?
Thanks
I'd probably refactor it slightly:
const [AddSessionInput, {error}] = useMutation(QUERY_STRING);
const runAddSessionInput = async () => {
await AddSessionInput({ variables });
};
In your onClick:
return (
<Button variant="primary" onClick={runAddSessionInput} />
);

Unable to use bootstrap-react modal in stateless function

What I want to do is add bootstrap-react modal and fire it from a stateless function. All the examples I can find requires changing the "show" in the state of component, but since Im not using af component I don't really have an idea how to do it.
https://react-bootstrap.github.io/components/modal/
https://react-bootstrap.github.io/components/modal/
You need state somewhere to show the modal. You can use hooks to do it in functional (not really "stateless") component using useState.
function App() {
const [open, setOpen] = useState(false);
return (
<>
<Button variant="primary" onClick={() => setOpen(true)}>
Launch demo modal
</Button>
<Modal show={open} onHide={() => setOpen(false)}>
<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={() => setOpen(false)}>
Close
</Button>
<Button variant="primary" onClick={() => setOpen(false)}>
Save Changes
</Button>
</Modal.Footer>
</Modal>
</>
);
}
codesandbox: https://codesandbox.io/embed/z2ky5l128l
If you don't want to do it then you need to pass prop from component that is higher in tree, like:
class App extends React.Component {
state = {
open: true,
}
render() {
return <ModalComponent open={open} hide={() => this.setState({open: false})} />
}
}
function ModalComponent = ({open, hide}) => (
<Modal show={open} onHide={hide}>
<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={hide}>
Close
</Button>
</Modal.Footer>
</Modal>
)
just pass visible state from parrent like below
class parent extends Component {
state = {
modalVisibility : false
}
handleModalVisibility = (action)=> this.setState({modalVisibility : action})
return (
<div>
<button onClick={this.handleModalVisibility.bind(this,true)} >Show Modal</button>
//use this props to show or cancel the modal
<ModalComponent visibility ={this.state.modalVisibility} handleModal={this.handleModalVisibility} />
</div>
)
}
I guess you can do that with useState
https://reactjs.org/docs/hooks-state.html

Resources