I'm using the Snackbar component from the Material-UI framework but I can't make it work correctly because the Snackbar shows only the first time, from the second message the Snackbar remain closed.
Here is the code I used to wrap the Snackbar:
import Snackbar from "@material-ui/core/Snackbar";
import { useState } from "react";
export default function Notification({ message }) {
const [value, setValue] = useState(message);
return (
<Snackbar
key={Math.random()}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center'
}}
open={value ? true : false}
autoHideDuration={5000}
message={value}
onClose={() => { console.log('snackbar closed'); setValue('') }}
/>
)
};
I use this component to show the result when the user submit a form. For example when the submit is succesful the message 'operation completed' is shown, but if the server doesn't validate the submission a message error is shown. Here is the code:
function InnerForm({ mode, detail, entity }) {
const isCreateMode = mode === 'create';
const schema = createSchema(entity);
const {
handleSubmit,
formState: { errors },
control,
setValue
} = useForm({
defaultValues: detail,
resolver: yupResolver(schema)
});
const [submitResponse, setSubmitResponse] = useState();
const onSubmit = async data => {
const operation = isCreateMode ?
entity.Client.create(data) :
entity.Client.update(data);
const response = await operation;
setSubmitResponse(response);
console.log(response);
if (response.success) {
if (isCreateMode) {
const autoField = entity.Fields.find(({ auto }) => auto);
if (autoField) {
setValue(autoField.id, response.content[autoField.id]);
}
}
}
};
return (
<>
{
submitResponse ?
submitResponse.success ?
<Notification message='operation completed' /> :
submitResponse.problem ?
<Notification message={submitResponse.problem} /> :
<Notification message='operation failed' />
: null
}
<form onSubmit={handleSubmit(onSubmit)}>
{
entity.Fields.map(field => {
const props = {
control,
id: field.id,
label: field.label,
error: errors[field.id]?.message,
multiline: field.type === 'text',
loadOptions: field.loadOptions,
getOptionLabel: field.getOptionLabel,
readonly: submitResponse?.success || field.auto || (field.key && !isCreateMode)
};
const Component =
field.type === 'string' ? TextInput :
field.type === 'datetime' ? DatetimeInput :
field.type === 'text' ? TextInput :
field.type === 'entity' ? SelectInput :
field.type === 'bool' ? CheckboxInput :
TextInput;
return <Component {...props} />
})
}
<SubmitButton isCreateMode={mode === 'create'} readonly={submitResponse?.success} />
</form>
</>
The test I do is the following:
It does not look like you're updating state
once it receives new props
, only initializing the state
the first time it's created.
You could try to update state
when it's called a second time.
You could also keep the open
state inside the InnerForm
component, and add a callback function as a parameter to Notification
that would be called in onClose
that would update the state of the Snackbar
inside InnerForm
Example of the second suggestion:
In InnerForm
const [isOpen, setIsOpen] = useState(false);
const [message, setMessage] = useState(message);
const callback = () => {
setValue(false)
}
// In render() you need to add this line.
<Notification message={message} isOpen={isOpen} onClose={callback}/>
In Notification
export default function Notification({ message, isOpen, onClose }) {
return (
<Snackbar
key={Math.random()}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center'
}}
open={isOpen}
autoHideDuration={5000}
message={message}
onClose={onClose}
/>
)
};
Finally, you just have to update message
and isOpen
in InnerForm
where you currently call the Notification
function
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With