【问题标题】:React hooks and Material-UI: Snackbar shows once but never againReact hooks 和 Material-UI:Snackbar 显示一次但不再显示
【发布时间】:2020-04-30 04:21:30
【问题描述】:

我已在此处隔离了我的问题,因此您可以轻松地重现此问题。 重现步骤:

第 1 步: 创建一个 React 应用并将material-ui 添加到项目中:

prompt> create-react-app mui-test
prompt> cd mui-test
prompt> yarn add @material-ui/core @material-ui/icons

第 2 步:更改以下文件:

index.tsx

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'

ReactDOM.render(
    <App />,
  document.getElementById('root')
)

App.tsx

import React, { useState } from 'react'
import { Button, Snackbar } from '@material-ui/core'

interface MessageComponentProps { messages: string[] }

export const MessageComponent: React.FC<MessageComponentProps> = ({ messages }) => {
  console.log("Render MessageComponent... messages: ", messages)
  console.log("messages.length > 0: ", messages.length > 0);

  // This shows the Snackbar once but when I reclick the submit button,
  // it doesn't do it again.
  const [showMessage, setShowMessage] = useState(true)

  const onClose = () => {
    console.log("calling onClose()...")
    setShowMessage(false)
  }

  if (messages.length === 0) return <></>

  return <>
    <Snackbar
      anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
      key={`top,center`}
      open={showMessage}

      // eventurally I want to display all messages but this will work for now.
      message={messages[0]}
      onClose={onClose}
    />
    Proof that Snackbar should be rendered here: {messages[0]}
  </>
}

export const PageComponent: React.FC = () => {
  console.log("Render PageComponent...")
  const [errors, setErrors] = useState<string[]>([])

  const onSubmit = (e: any) => {
    e.preventDefault()

    // simulates a collection of error messages sent back from the server to
    // show to the user.
    setErrors(['Foo ' + Math.random(), 'Bar'])
  }

  return <>
    <MessageComponent messages={errors} />
    <form onSubmit={onSubmit} >
      <Button type="submit" color="primary" variant="contained">Submit</Button>
    </form>
    <p>
      What I'm trying to accomplish here is that whenever this button is clicked,
      The snackbar should show and then be cleared when the user clicks away from
      the message. It only does this the first time but doesn't any of the
      consecutive clicks.
    </p>
  </>
}

function App() {
  console.log("Render App...")

  return <PageComponent />
}

export default App

问题: 我可以弹出SnackBar 消息,但是当我尝试关闭它时,尽管调用了onClose 方法,但它永远不会出现。当我尝试修复此问题时,它永远不会真正打开(请参阅代码中的一些 cmets,了解我在此处尝试执行的操作)

在某一时刻,我可以让SnackBar 关闭。但是,点击Submit 按钮应该会导致SnackBar 消息再次弹出,但在第一次之后就不再弹出了。让它回来的唯一方法是我重新加载页面然后再次单击按钮。

我对 React 还是很陌生,所以我正在努力解决这个问题,但我暗中怀疑这个配方需要 useEffect

【问题讨论】:

    标签: reactjs typescript material-ui react-hooks


    【解决方案1】:

    在您的消息组件中使用useEffect 并收听messages

    const [showMessage, setShowMessage] = useState(true);
      useEffect(() => {
        if (messages.length > 0) {
          setShowMessage(true);
        }
      }, [messages]);
    

    为了关闭snackbar,您需要提供action prop 或autoHideDuration

         <Snackbar
            anchorOrigin={{ vertical: "top", horizontal: "center" }}
            key={`top,center`}
            open={showMessage}
            autoHideDuration={6000}
            // eventurally I want to display all messages but this will work for now.
            message={messages[0]}
            onClose={onClose}
            action={
              <React.Fragment>
                <IconButton
                  size="small"
                  aria-label="close"
                  color="inherit"
                  onClick={onClose}
                >
                  X
                </IconButton>
              </React.Fragment>
            }
          />
    

    code is here 的工作副本

    【讨论】:

    • 这行得通。虽然不需要actionautoHideDuration。我将在 Mui 的 lab 命名空间中使用 Alert 组件,它确实具有这些选项。
    【解决方案2】:

    我想到了两个快速的解决方案:

    {
      Boolean(showMessage) && ----------------Do this
      <Snackbar
      anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
      key={`top,center`}
      open={Boolean(showMessage)} --------------- or do this
    
      // eventurally I want to display all messages but this will work for now.
      message={messages[0]}
      onClose={onClose}
    />}
    

    【讨论】:

    • 或者你可以通过任何'codesandbox'分享你的工作代码以获得详细的解决方案。
    • 查看其他答案。他设置了一个代码沙盒解决方案。我只需要一个useEffect 钩子,反正我就是这么想的。
    猜你喜欢
    • 2021-09-14
    • 1970-01-01
    • 2013-08-23
    • 1970-01-01
    • 2020-07-20
    • 2016-06-04
    • 1970-01-01
    • 2020-07-25
    • 1970-01-01
    相关资源
    最近更新 更多