#reactjs #material-ui
Вопрос:
Я использую компонент Snackbar из фреймворка Material-UI, но я не могу заставить его работать правильно, потому что панель закусок отображается только в первый раз, со второго сообщения панель закусок остается закрытой.
Вот код, который я использовал для упаковки закусочной:
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('') }}
/>
)
};
Я использую этот компонент для отображения результата, когда пользователь отправляет форму. Например, при успешной отправке отображается сообщение «операция завершена», но если сервер не проверяет отправку, отображается сообщение об ошибке. Вот код:
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 amp;amp; !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>
</>
Тест, который я провожу, заключается в следующем:
- Сначала я компилирую форму с неверными данными и выполняю команду отправить => >Ок, на панели закусок появляется сообщение об ошибке.
- Во-вторых, я исправляю данные и выполняю новую отправку => >Отправка прошла успешно, но сообщение об успешном выполнении не отображается
Ответ №1:
Это не похоже на то , что вы обновляете state
, как только он получает новое props
, только инициализируете state
его при первом создании.
Вы можете попробовать обновить state
его, когда он будет вызван во второй раз.
Вы также можете сохранить open
состояние внутри InnerForm
компонента и добавить функцию обратного вызова в качестве параметра Notification
, который будет вызван, onClose
чтобы обновить состояние Snackbar
внутри InnerForm
Пример второго предложения:
В 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}/>
В 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}
/>
)
};
Наконец, вам просто нужно обновить message
и isOpen
в InnerForm
том месте, где вы в данный момент вызываете Notification
функцию
Комментарии:
1. Спасибо за помощь, вы решили мою проблему. Тогда компонент не сбрасывает свое состояние при изменении реквизита?
2. Компоненты не обновляют состояние автоматически при получении новых реквизитов. Причина, по которой вы получили сообщение внутри состояния, заключалась в том, что состояние инициализируется значением сообщения во время первого рендеринга. Я считаю, что это способ обновить реквизит с помощью крючков:
useEffect(() => { setValue(message) }, [message]);
. Если вы предпочитаете, вы можете использовать свой код с этим изменением. Хотя лично я считаю, что для родительского компонента имеет больше смыслаInnerForm
решать, когдаNotification
он должен быть открыт, как в моем примере в ответе выше.