【问题标题】:Material ui Snackbar show only once and doesn't reopenMaterial ui Snackbar 仅显示一次并且不会重新打开
【发布时间】:2021-06-16 12:55:16
【问题描述】:

我正在使用 Material-UI 框架中的 Snackbar 组件,但我无法使其正常工作,因为 Snackbar 仅第一次显示,从第二条消息开始,Snackbar 保持关闭。

这是我用来包装 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('') }}
        />
    )
};

当用户提交表单时,我使用这个组件来显示结果。例如,当提交成功时,会显示消息“操作已完成”,但如果服务器未验证提交,则会显示消息错误。代码如下:

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>
    </>

我做的测试如下:

  • 首先,我用无效数据编译表单并执行提交 => 好的,snackbar 出现错误消息
  • 其次,我更正数据,执行新的提交=> 提交成功,但是没有显示成功信息

【问题讨论】:

    标签: reactjs material-ui


    【解决方案1】:

    您似乎不会在收到新的props 后更新state,只是在第一次创建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}
        />
    )
    };
    

    最后,您只需在当前调用Notification 函数的InnerForm 中更新messageisOpen

    【讨论】:

    • 感谢您的帮助,您解决了我的问题。那么,当 props 发生变化时,组件不会重置其状态?
    • 组件在收到新的 props 时不会自动更新状态。您在 state 中收到消息的原因是因为 state 在第一次渲染期间被初始化为 message 的值。我相信这是使用钩子更新道具的方法:useEffect(() =&gt; { setValue(message) }, [message]);。如果您愿意,可以使用您的代码进行此更改。不过,我个人认为父组件InnerForm 决定何时打开Notification 更有意义,就像我在上面答案中的示例一样。
    猜你喜欢
    • 2018-06-06
    • 2021-02-20
    • 2021-03-07
    • 1970-01-01
    • 2020-10-08
    • 1970-01-01
    • 2019-07-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多