I have this Alert component to be used just to have a message that says "Successfully submitted" and I'm trying to use thin in a parent component. However, nothing shows in the parent component.
AlertComponent
import React, { useState } from "react";
import { Snackbar, Alert } from "#mui/material";
const AlertComponent = () => {
const [open, setOpen] = useState(false);
const handleClick = () => {
setOpen(true);
};
const handleClose = (event, reason) => {
if (reason === "clickaway") {
return;
}
setOpen(false);
};
return (
<div>
{" "}
<Snackbar open={open} autoHideDuration={6000} onClose={handleClose}>
<Alert onClose={handleClose} severity="success">
Successfully Submitted!
</Alert>
</Snackbar>
</div>
);
};
export default AlertComponent;
Parent Component
const ParentComponent = () => {
const [open, setOpen] = useState(false);
const onSubmit = async (data) => {
//codes to submit the data
setOpen(true); //trigger the alert component
};
return (
<div>
//form here to submit
<AlertComponent open={open} />
</div>
);
};
export default ParentComponent;
How can I fix this? Thank you.
Although #Ghader Salehi commented already the solution but if anyone is not sure how to control the alert from parent here is the code.
AlertComponent.js
import React from "react";
import { Snackbar, Alert } from "#mui/material";
function AlertComponenet(props) {
const { open, handleClose } = props;
return (
<div>
{" "}
<Snackbar open={open} autoHideDuration={6000} onClose={handleClose}>
<Alert onClose={handleClose} severity="success">
Successfully Submitted!
</Alert>
</Snackbar>
</div>
);
}
export default AlertComponenet;
Parent Component (In my code-sandbox I used App.js)
import React, { useState } from "react";
import "./styles.css";
import AlertComponent from "./AlertComponent";
export default function App() {
const [open, setOpen] = useState(false);
const handleClick = () => {
setOpen(true);
};
const handleClose = (event, reason) => {
if (reason === "clickaway") {
return;
}
setOpen(false);
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={handleClick}>Show Alert</button>
<AlertComponent open={open} handleClose={handleClose} />
</div>
);
}
Related
I am using Material UI (V4). There is a Customized SnackBar component being used to display the messages from backed, like success and failure messages. But, I am unable to copy the message shown on the snackbar component. This issue is seen only on Chrome (the text selection is working fine on Safari browser). Here is the sample code I'm using:
import React from 'react';
import Button from '#material-ui/core/Button';
import Snackbar from '#material-ui/core/Snackbar';
import MuiAlert from '#material-ui/lab/Alert';
import { makeStyles } from '#material-ui/core/styles';
import { Icon } from '#material-ui/core';
import SmsFailedIcon from '#material-ui/icons/SmsFailed';
const successIcon = () => (
<Icon>
<SmsFailedIcon />
</Icon>
);
const failedIcon = () => (
<Icon>
<SmsFailedIcon />
</Icon>
);
function Alert(props) {
return (
<MuiAlert
elevation={6}
variant="filled"
{...props}
iconMapping={{ success: successIcon, error: failedIcon }}
/>
);
}
const useStyles = makeStyles((theme) => ({
root: {
width: '100%',
'& > * + *': {
marginTop: theme.spacing(2),
},
},
}));
export default function CustomizedSnackbars() {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const handleClick = () => {
setOpen(true);
};
const handleClose = (event, reason) => {
setOpen(false);
};
return (
<div className={classes.root}>
<Button variant="outlined" onClick={handleClick}>
Open success snackbar
</Button>
<Snackbar open={open} autoHideDuration={6000} onClose={handleClose}>
<Alert onClose={handleClose} severity="success">
This is a success message!
</Alert>
</Snackbar>
</div>
);
}
Can anyone please advise ?
This is my reusable component:
import {
Dialog,
DialogContent,
DialogContentText,
DialogTitle,
Divider,
Button,
DialogActions,
} from "#mui/material";
const Modal = ({ title, subtitle, children, isOpen, handleClose }) => {
return (
<Dialog open={isOpen} onClose={handleClose}>
<DialogTitle>{title}</DialogTitle>
<DialogContent>
<DialogContentText>{subtitle}</DialogContentText>
<Divider />
{children}
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="error">
Close
</Button>
</DialogActions>
</Dialog>
);
};
export default Modal;
Parent component where I use this here:
const [isOpen, setisOpen] = useState(false);
const [isOpenDialog, setIsOpenDialog] = useState(false);
const handleDialogOpen = () => {
setisOpen(true);
};
const handleDialogClose = () => {
setisOpen(false);
};
const handleOpen = () => {
setIsOpenDialog(true);
};
const handleClose = () => {
setIsOpenDialog(false);
};
<Modal
title="confirmation"
isOpen={isOpen}
children={sample}
handleClose={handleDialogClose}
/>
<Button
color="error"
onClick={
() => handleDialogOpen}
>
Delete
</Button>
It does not show any error in the console and the app does not crash. How can I fix this? Also how can I add a button where the user can say yes since at the moment the modal only have a buttin to close it
There's a lot to unpack here. Here's a solution:
import {
Dialog,
DialogContent,
DialogContentText,
DialogTitle,
Divider,
Button,
DialogActions
} from "#mui/material";
const Modal = ({ title, subtitle, children, isOpen, handleClose }) => {
const handleConfirm = () => {
alert("You Agreed!");
handleClose();
};
return (
<Dialog open={isOpen} onClose={handleClose}>
<DialogTitle>{title}</DialogTitle>
<DialogContent>
<DialogContentText>{subtitle}</DialogContentText>
<Divider />
{children}
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="error">
Cancel
</Button>
<Button onClick={handleConfirm} color="primary">
Agree
</Button>
</DialogActions>
</Dialog>
);
};
export default Modal;
Here's the parent:
import Modal from "./modal";
import { useState } from "react";
import { Button } from "#mui/material";
export default function App() {
const [isOpen, setisOpen] = useState(false);
const handleOpen = () => {
setisOpen(true);
};
const handleClose = () => {
setisOpen(false);
};
return (
<div className="App">
<Modal title="confirmation" isOpen={isOpen} handleClose={handleClose} />
<Button color="primary" onClick={handleOpen}>
I Agree
</Button>
</div>
);
}
Here's the sandbox:
In react.js, I want setShowModal to be false when the Backdrop component is clicked and the Backdrop component to be hidden, but setShowModal is not false and does not even show console.log ('a').
import { useState } from 'react';
import Backdrop from './Backdrop';
import Modal from './Modal';
function Todo(props) {
const [showModal, setShowModal] = useState(false);
function showModalHandler() {
setShowModal(true);
}
function closeModalHandler() {
setShowModal(false);
console.log('a');
}
return (
<div className='card'>
<h2>{props.text}</h2>
<div className='actions'>
<button className='btn' onClick={showModalHandler}>
Delete
</button>
</div>
{showModal && <Modal />}
{showModal && <Backdrop onClick={closeModalHandler} />}
</div>
);
}
export default Todo;
it seems that there was a problem with the binding of the closeModalHandler function. I've made some changes to your code and it is actually closing the modal and dropping the 'a' in the console.
Defining the functions as arrow functions use to help in these cases.
Hope it works to you.
import { useState } from 'react';
function Todo(props) {
const [showModal, setShowModal] = useState(true);
const showModalHandler = () => {
setShowModal(true);
}
const closeModalHandler = () => {
setShowModal(false);
console.log('a');
}
return (
<div className='card'>
<h2>{props.text}</h2>
<div className='actions'>
<button className='btn' onClick={() => showModalHandler()}>
Delete
</button>
</div>
{showModal && <button> ShowModalIsActive</button>}
{showModal && <button onClick={() => closeModalHandler()}>Button</button>}
</div>
);
}
export default Todo;
I am creating a simple application using react and I have two components: Form and Modal. The Modal should be opened when the Form is submitted. How to change the state of the Modal component to achieve this ?
This is the code for the Form.js compent:
import Modal from './Modal'
export default function Form() {
const handleSubmit = (e) => {
e.preventDefault()
}
return (
<form onSubmit={handleSubmit}>
<SuccessModal />
<div className='mt-1'>
...
</form>
)}
This is the code for the Modal.js compent:
export default function Modal() {
const [open, setOpen] = useState(false)
return (
<Transition.Root show={open} as={Fragment}>
<Dialog
as='div'
static
open={open}
onClose={setOpen}
>
...
</Dialog>
</Transition.Root>
I tried to pass this state as a property, but I think I'm doing something wrong. I would be very grateful if any of you could explain to me the principle of how this works.
You can have modal state in Form.js and then pass the state as props to Modal.js.
On Form submit set the modal state.
Form.js
import Modal from './Modal'
export default function Form() {
const [open, setOpen] = useState(false)
const handleSubmit = (e) => {
e.preventDefault()
...
setOpen(true);
}
return (
<>
<form onSubmit={handleSubmit}>
<SuccessModal />
<div className='mt-1'>
...
</form>
{open && <Modal open={open} setOpen={setOpen} />}
</>
)}
Modal.js
export default function Modal({ open, setOpen }) {
return (
<Transition.Root show={open} as={Fragment}>
<Dialog
as='div'
static
open={open}
onClose={setOpen}
>
...
</Dialog>
</Transition.Root>
the state controller useState should be in the parent, not the Modal.
Then you can simply use a prop to define the open state.
One way we do this at my work is creating a custom hook for it:
// stateless modal component
export default function Modal({ open }) {
return (
<Transition.Root show={open} as={Fragment}>
<Dialog
as='div'
static
open={open}
onClose={setOpen}
>
...
</Dialog>
</Transition.Root>
}
// custom hook
export function useModal({ initialState }) {
const [open, setOpen] = useState(initialState)
return {
component: <Modal open={open} />,
setOpen,
}
}
// parent code
import { useModal } from './Modal'
export default function Form() {
const modal = useModal(false)
const handleSubmit = (e) => {
e.preventDefault()
modal.setOpen(true)
}
return (
<form onSubmit={handleSubmit}>
{modal.component}
<div className='mt-1'>
...
</form>
)}
You can try lifting the state of the child (Modal) to the state of the parent (Form). Refer this
You don't use state for show or hide Modal component. Use the props. With props components will be working like this:
import Modal from './Modal'
interface IFormProps {}
interface IFormState {
isModalOpen: boolean
}
export class Form extends React.Component<IFormProps, IFormState> => {
state: IFormState = {
isModalOpen: false,
}
const handleSubmit = (e): void => {
this.setState({ isModalOpen: true })
e.preventDefault()
}
const handleModalClose = (): boolean => {
this.setState({ isModalOpen: false })
}
return (
<form onSubmit={handleSubmit}>
<Modal isOpen={this.state.isModalOpen} handleClose={this.handleModalClose} />
<div className='mt-1'>
...
</form>
)}
interface IModalProps {
isOpen: boolean
handleClose: () => boolean
}
interface IModalState {}
export class Modal extends React.Compnent<IModalProps, IModalState> {
const { isOpen, handleClose } = this.props
return (
<Transition.Root show={isOpen} as={Fragment}>
<Dialog
as='div'
static
open={isOpen}
onClose={handleClose}
>
...
</Dialog>
</Transition.Root>
I use Antd. I have Modal Window which consist Form. I want to focus in Input Field when user open the modal widnow. How i can do it in functional component? I try this but in not work for me:
const EditForm = ({visible, widget, onSave, onCancel}) => {
const nameInput = useRef();
useEffect(() => nameInput.current && nameInput.current.focus());
const [form] = Form.useForm();
return (
<div>
<Modal
visible={visible}
title='Edit'
okText='Save'
cancelText='Cancel'
onCancel={onCancel}
onOk={() => {
form
.validateFields()
.then(values => {
form.resetFields();
onSave(values);
})
.catch(info => {
console.log('Validate Failed:', info);
});
}}
>
<Form
{...formItemLayout}
layout={formLayout}
form={form}
>
<Form.Item />
<Form.Item
name='nameWidget'
label='Name'
>
<Input name='nameWidget' ref={nameInput} onChange={handleChangeName} placeholder='Введите новое название' />
</Form.Item>
</Form>
</Modal>
</div>
);
};
try this way.
good luck ;)
import React, {useState, useRef, useEffect} from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import './index.css';
import { Modal, Button, Input, Form } from 'antd';
const App = () => {
const [visible, setVisible] = useState(false)
const myRef = useRef();
/*
* This is the main different
*/
useEffect(()=>{
if (myRef && myRef.current) {
const { input } = myRef.current
input.focus()
}
})
const showModal = () => {
setVisible(true)
};
const handleOk = e => {
setVisible(false)
};
const handleCancel = e => {
setVisible(false)
};
return (
<>
<Button type="primary" onClick={showModal}>
Open Modal with customized button props
</Button>
<Modal
title="Basic Modal"
visible={visible}
onOk={handleOk}
onCancel={handleCancel}
okButtonProps={{ disabled: true }}
cancelButtonProps={{ disabled: true }}
>
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
<Form>
<Form.Item>
<Input ref={myRef} />
</Form.Item>
</Form>
</Modal>
</>
);
}
ReactDOM.render(<App />, document.getElementById('container'));