【问题标题】:useEffect to show snackbar if message is not null, and how to use useState with that?如果消息不为空,useEffect 显示小吃栏,以及如何使用 useState?
【发布时间】:2019-09-11 23:47:22
【问题描述】:

如果消息不为空并显示小吃栏,我已经制作了一个组件来呈现。如果有人点击登录按钮,我已经集成了它,如果有错误,应该由小吃栏提示错误消息。但是当用户单击小吃栏并将其关闭时,如果用户再次单击登录按钮,则小吃栏将无法再次显示。当用户第一次点击登录按钮时效果很好,但其他时候它不会出现。在我的情况下,“文本”是我通过道具发送的错误消息。所以 useEffect 认为 const "text" 不为空,这就是为什么如果用户再次单击登录按钮,快餐栏不会出现。所以我的问题是,如果消息相同,我如何绕过这个,并再次显示小吃店无论消息是什么?

这是我一直在使用的代码:

const NotificationManager = (props) => {
  const { text, type } = props
  const [open, setOpen] = useState(true)
  useEffect(() => {
    setOpen(Boolean(text))

  }, [Boolean(text)])
  const handleClose = () =>{
    setOpen(false)
}
  console.log(Boolean(text))
  return (
    <Snackbar
    onClick={handleClose}
      anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
      autoHideDuration={3000}
      open={open}
      snackbarcontentprops={{
        'aria-describedby': 'snackbar-message-id'
      }}
    >
      <SnackbarContent
        style={Object.assign({
          background: styles[type] || styles['success']
        })}
        message={localize(text)}
      />
    </Snackbar>
  )
}

export default NotificationManager

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    如果我理解了这个问题,您可以通过添加另一个 useEffect 来完成它,它会在您隐藏通知时重置您的 open 状态:

    const AUTO_HIDE_DURATION = 3000;
    
    const NotificationManager = ({ text, isLoginClicked }) => {
      const [open, setOpen] = useState(true);
    
      const handleClose = () => {
        setOpen(false);
      };
    
      useEffect(() => {
        setOpen(Boolean(text));
      }, [Boolean(text)]);
    
      useEffect(() => {
        setTimeout(() => {
          if (open) {
            setOpen(!open);
          }
        }, AUTO_HIDE_DURATION);
      });
    
      return (
        <Snackbar
          onClick={handleClose}
          autoHideDuration={AUTO_HIDE_DURATION}
          open={open || isLoginClicked}
        >
          <SnackbarContent message={localize(text)} />
        </Snackbar>
      );
    };
    
    export default NotificationManager;
    
    

    注意:您应该将代码上传到 codesandbox 之类的沙箱中,我们不知道其他道具及其对您的组件状态的影响。

    【讨论】:

    • 一旦我点击小吃栏并关闭它,我就无法再次打开它,因为消息还是一样的。所以我需要在第二次点击登录按钮时再次打开它等等......
    • 尝试在你的登录按钮上引入另一个更新的道具,检查isLoginClicked
    【解决方案2】:

    首先,NotificationManager 对用户是否点击登录按钮一无所知。所以它不应该将open 状态保留在内部。

    您应该将useState 向上移动一级,例如LoginContainer,然后将[open, setOpen] 对向下传递到NotificationManager 作为道具。这样,两个组件都可以访问setOpen,只要用户点击登录,就可以访问setOpen(true)

    其次,你有 2 个布尔状态变量,4 种可能的组合

                    open: true  open: false
    text: true      true        false
    text: false     false       false
    

    答案很明显,您应该停止使用open 作为最终切换状态变量。 useEffect 完全没有必要。而是使用:

    const reallyShouldOpen = Boolean(text) & open;
    

    第三,当autoHideDuration 结束时,你应该将open 切换回false,这样当人们再次点击时,他们可以重新切换。 (与@DannisVash 建议的相同)

      useEffect(() => {
        setTimeout(() => {
          if (open) {
            setOpen(!open);
          }
        }, AUTO_HIDE_DURATION);
      });
    

    【讨论】:

      猜你喜欢
      • 2021-04-13
      • 2021-06-03
      • 2021-08-15
      • 1970-01-01
      • 2017-09-28
      • 1970-01-01
      • 2020-04-13
      • 2020-05-22
      • 1970-01-01
      相关资源
      最近更新 更多