Rendering Modal Popup - javascript

My goal is to launch a modal pop-up during the event a button is clicked. I've been having issues making the Axios API call to the function that contains the modal. The process of the API call has been listed below:
First: This is the button where the Axios post request is made (addToCart) (works fine)
<button className="button is-primary" onClick={addToCart}>
ADD TO CART
</button>
Second: This is the Axios post request that makes a call to the modal pop-up (Example()) (works fine)
const addToCart = () => {
Axios.post(
//standard backend API call is made here
)
.then((res) => {
console.log("post called")
Example(); //I want to launch my modal when this state is reached
})
.catch((err) => {
if (err.response && err.response.status === 401) {
setIsLoggedIn(false);
}
});
Third: This is the modal that I'd like to popup but have been having issues rendering the function (Issue)
https://react-bootstrap.github.io/components/modal/
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 />);
I receive the following error:
Line 38:3: 'render' is not defined no-undef
How can I properly render my modal pop-up?

Instead of having a show state in your Example component, receive this data in a prop. In addition, you'll also want to pass some callbacks to the component to be able to react to certain events (e.g. clicking "Close" or "Save Changes").
I'd do the following:
const Example = ({ show, onClose, onSave }) => (
<Modal show={show} onHide={onClose}>
<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={onClose}>
Close
</Button>
<Button variant="primary" onClick={onSave}>
Save Changes
</Button>
</Modal.Footer>
</Modal>
)
This way you could always render the Example component in some parent component and show it conditionally, like so:
const SomeParentComponent = () => {
const [showExample, setShowExample] = useState(false)
const addToCart = () => {
Axios.post("http://example.com/api/add-to-cart")
.then((res) => {
console.log("post called")
setShowExample(true)
})
.catch((err) => {
if (err.response && err.response.status === 401) {
setIsLoggedIn(false);
}
})
}
return (
<>
<button className="button is-primary" onClick={addToCart}>
ADD TO CART
</button>
<Example
show={showExample}
onClose={() => setShowExample(false)}
onSave={() => setShowExample(false)}
/>
</>
)
}

Related

How can I use a function from my hook in a component file?

I have two files, one is my hook for my react-table and the second file is a modal. My problem is I made a delete function in my hook and need to use that function in my modal file.
How can I choose a specific function to use in my component modal from my hook?
The hook file:
const useTableResource = () => {
const deleteButton = async (row) => {
await axios.delete(`test/api/resources?_id=${row.original._id}`);
console.log("deleted")
};
const DeleteHooks = (hook) => {
hook.visibleColumns.push((colums) => [
...colums,
{
id: 'delete',
accessor: () => 'delete',
Cell: ({row}) => <div onClick={(event) => event.stopPropagation()}>
<TrashButton/>
</div>
}
]);
};
};
export default useTableResource;
The ModalComponent where I need to call the delete Button function:
const TrashModal = ({show, handleClose, handleConfirm}) => {
return (
<>
<Modal show={show} onHide={handleClose} className="Trashmodal">
<Modal.Header closeButton>
<Modal.Title>attention</Modal.Title>
</Modal.Header>
<Modal.Body>Confirm </Modal.Body>
<Modal.Footer className="FooterTrash">
<Button className="btn btn-sm" variant="secondary" onClick={handleClose} autoFocus={true}>Close</Button>
<Button className="btn btn-sm btn-primary" onClick={//i need use here deleteButton function} autoFocus={true}>
<i className="fa fa-check" aria-hidden="true"></i>Confirm</Button>
</Modal.Footer>
</Modal>
</>
);
};

How to stop useEffect from loading my modal multiple times?

I have a function based React view which has a modal that loads based on the presence of an item in the local storage:
function myView() {
...
function HelpModal() {
const [show, setShow] = useState(false);
useEffect(()=>{
let pop_status = localStorage.getItem('this-page-modal');
if(!pop_status){
setShow(true);
}
},[])
if(!setShow) return null;
const handleClose = () => {
localStorage.setItem('this-page-modal', '1');
setShow(false);
};
const handleShow = () => setShow(true);
return (
<>
<Button variant="primary" onClick={handleShow}>
Button text
</Button>
<Modal show={show} onHide={handleClose}>
<Modal.Body>
<p>Hey! This is a modal.</p>
</Modal.Body>
<Modal.Footer>
<Button variant="primary" onClick={handleClose}>
Close
</Button>
</Modal.Footer>
</Modal>
</>
);
}
return (
<div>
<Container style={{marginTop: "1em"}}>
<Row>
<Col><h1>My View</h1></Col>
<Col><span style={{float: "right"}}> <HelpModal /></span></Col>
</Row>
</Container>
</div>
);
}
The problem: When I load the page, the modal flickers and loads 2 or 3 times.
How do I make it load only once? Any suggestions will be appreciated.
For the general case, you can use useLayoutEffect to make the update occur quicker, near instantaneously, instead of a bit after a repaint with useEffect.
Also, the if(!setShow) return null; line is completely superfluous because the useState setter function will always be a function, which is truthy.
useLayoutEffect(() => {
const pop_status = localStorage.getItem('this-page-modal');
if (!pop_status) {
setShow(true);
}
}, []);
But since the function inside the effect is completely synchronous, it'd make more sense to use the storage value as the initial value for the show state, instead of calling the state setter; you an remove the effect entirely.
const [show, setShow] = useState(!localStorage.getItem('this-page-modal'));
const handleClose = () => {
localStorage.setItem('this-page-modal', '1');
setShow(false);
};
const handleShow = () => setShow(true);
return (
// ...
Your setup could be causing re-renders based upon code not represented here so it's difficult to diagnose the exact issue. One thing to try might be to put a console.log statement in various function scopes to see how many times it's being re-rendered on load. Aside from that, (and concurring with previous answer) I think you might be able to simplify your code down a bit and get the same result by having the conditional render be straight from localStorage. Maybe something like:
function HelpModal() {
const [show, setShow] = useState(localStorage.getItem("this-page-modal"));
const handleClose = () => {
setShow(false);
localStorage.setItem("this-page-modal", false);
};
const handleShow = () => {
setShow(true);
localStorage.setItem("this-page-modal", true);
};
return (
<>
<Button variant="primary" onClick={handleShow}>
Button text
</Button>
<Modal show={show} onHide={handleClose}>
<Modal.Body>
<p>Hey! This is a modal.</p>
</Modal.Body>
<Modal.Footer>
<Button variant="primary" onClick={handleClose}>
Close
</Button>
</Modal.Footer>
</Modal>
</>
);
}
function myView() {
return (
<>
<HelpModal />
</>
);
}

Dispatch a Redux action from a modal in React

I'm a begginer in React and I'm trying to find a way to dispatch a redux action from a modal.
I have a list of products and a button 'add to bag' under each image. When we click on the button 'add to bag', I want a modal to appear that ask for a confirmation. The action need to be dispatched when the user click on the confirm button inside de modal window.
The action need to grab the item object.
All is working fine ...but I'm not able to pass the item into the action when I want to launch the action from the modal.
So, my problem is not the Redux side but the modal part ( I use React-bootstrap for the modal).
I have this error message : 'item' is not defined
I'm not sure I understand exactly why this does'nt work and I failed to find a solution. I tried so many things but it's just not working.
Is there a simple way to add/pass the item data into the modal easily ?
Help would be very appreciated ! :)
Thanks a lot !!!
Here are part of my files :
Product.js
import { Modal } from "react-bootstrap";
function Products(props) {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
return (
<div>
<CardGroup>
{_.map(props.data, (item) => (
<Col>
...Some code here
<div>
<div>
{item.name.map((item) => (
<ul key={item}>{item}</ul>
))}
</div>
<div>
<button onClick={() => {handleShow()}}>
Add to bag
</button>
</div>
</div>
</Col>
))}
</CardGroup>
<Modal show={show} onHide={handleClose}>
<Modal.Body>Please confirm you want to add this product</Modal.Body>
<Modal.Footer>
<button
onClick={props.addProductToBasket(item)}
>
Confirm
</button>
<button onClick={handleClose}>Cancel</button>
</Modal.Footer>
</Modal>
</div>
);
}
const mapStateToProps = (state) => {
return { code here ...};
};
const mapDispatchToProps = (dispatch) => {
return {
addProductToBasket: (id) => dispatch(addProductToBasket(id)),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Products);
Here is the part of my Product.js file im my Store/actions folder
export const addProductToBasket = (id) => {
return {
type: ADD_PRODUCTD_TO_BASKET,
payload: id,
};
};
Since you only show the modal if an item was clicked, store the item or null instead of Boolean in the state, and open and close the modal accordingly:
function Products(props) {
const [selectedItem, setShowItem] = useState(null); // item for open model or null for closed
const handleClose = () => setShowItem(null);
const handleShow = item => setShowItem(item);
return (
<div>
<CardGroup>
{_.map(props.data, (item) => (
<Col>
...Some code here
<div>
<div>
{item.name.map((item) => (
<ul key={item}>{item}</ul>
))}
</div>
<div>
<button onClick={() => handleShow(item)}>
Add to bag
</button>
</div>
</div>
</Col>
))}
</CardGroup>
<Modal show={selectedItem !== null} onHide={handleClose}>
<Modal.Body>Please confirm you want to add this product</Modal.Body>
<Modal.Footer>
<button
onClick={() => props.addProductToBasket(selectedItem)}
>
Confirm
</button>
<button onClick={handleClose}>Cancel</button>
</Modal.Footer>
</Modal>
</div>
);
}
Not related, but it will make your life easier - use the object form of mapDispatchToProps that will save you the need to wrap with dispatch manually:
const mapDispatchToProps = {
addProductToBasket
};

React (Nextjs): render table row to boostrap modal onclick

I have the following Nextjs page using React bootstrap modal and a MUI datatables component:
const Start = () => {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
const options = {
onTableInit: rowData,
onRowClick: rowData => Testing(rowData),
}
return (
<Layout>
<Modal show={show} onHide={handleClose}>
<Modal.Header>
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>
Modal content
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
</Modal.Footer>
</Modal>
<MUIDataTable
title={"Datatable with modal onRowClick"}
data={data}
columns={columns}
options={options}
responsive="scrollFullHeight"
/>
</Layout>
)
}
export default Start;
The bootsrap modal works fine and opens onRowClick, I am also able to console log the rowData in a function when clicking a certain row:
function Testing(rowData) {
console.log(rowData)
);
I would like to achieve passing this rowData to the bootstrap modal accordingly when clicked on certain row.
I know I should be using the mapping, since it's an JSON object
{rowData.map(item => {
return <li key={item}>{item}</li>
}
)}
But how to integrate this into my current system? I get the error on rowData is not a function.

Rendering Modal using React Bootstrap

I'm new to react and thus the question,
I'm rendering a react-bootstrap Modal during form validation.
import React from 'react';
import {useState} from "react";
import {Button, Modal} from "react-bootstrap";
const CustomModal = (props) =>{
return (
<div>
<Modal show={true} animation={false}>
<Modal.Header closeButton>
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>{props.message}</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={...}}>
Close
</Button>
</Modal.Footer>
</Modal>
</div>
)
};
export default CustomModal;
How do I implement the onClick on the Buttonto close this Modal
You can modify your code as given below.
import React from 'react';
import {useState} from "react";
import {Button, Modal} from "react-bootstrap";
const CustomModal = (props) =>{
const [isModalOpen, setModal] = useState(true); // You can pass default state (true/false) from props as parameter into useState. i.e. useState(props.isModalOpen)
return (
<div>
<Modal show={isModalOpen} animation={false}>
<Modal.Header closeButton>
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>{props.message}</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={() => setModal(false)} >
Close
</Button>
</Modal.Footer>
</Modal>
</div>
)
};
export default CustomModal;
Add onHide={ () => setModal(false)} to <Modal... > for using closeButton
and for Button add setModal(false) to onClick.
const CustomModal = (props) =>{
const [isModalOpen, setModal] = useState(true); // You can pass default state (true/false) from props as parameter into useState. i.e. useState(props.isModalOpen)
return (
<div >
<Modal show={isModalOpen} onHide={ () => setModal(false)} animation={false}>
<Modal.Header closeButton>
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>{props.message}</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={() => setModal(false)} >
Close1
</Button>
</Modal.Footer>
</Modal>
</div>
)
};
for more code efficiency you can extract () => setModal(false) and put in function.
like handleClose() { setModal(false); }
const CustomModal = (props) =>{
const [isModalOpen, setModal] = useState(true); // You can pass default state (true/false) from props as parameter into useState. i.e. useState(props.isModalOpen)
const handleClose=({isOpen})=> { setModal(isOpen);//Do somthings els for example remove temporary variables
}
return (
<div >
<Modal show={isModalOpen} onHide={ () => handleClose(false)} animation={false}>
<Modal.Header closeButton>
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>{props.message}</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={() => handleClose(false)} >
Close1
</Button>
</Modal.Footer>
</Modal>
</div>
)
};
Currently you have a hard-coded value for show={true}. Instead, use a variable with the value of True. Then using a function with onClick, you can set the variable to false in order to close the modal.
e.g. show={isOpen}

Categories

Resources