React hooks и Material-UI: Snackbar показывает один раз, но никогда - PullRequest
0 голосов
/ 30 апреля 2020

Я выделил мою проблему здесь, чтобы вы могли легко воспроизвести это. Шаги для воспроизведения:

Шаг 1: создать приложение реагирования и добавить 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. Когда я пытаюсь это исправить, он никогда не открывается (см. Некоторые комментарии в коде для того, что я пытаюсь сделать здесь)

В какой-то момент я мог заставить SnackBar закрыться , Однако нажатие кнопки Submit должно привести к тому, что сообщение SnackBar снова появится, но никогда после первого раза. Единственный способ вернуть его - это перезагрузить страницу и нажать кнопку еще раз.

Я все еще новичок в React, поэтому я борюсь с этим, но у меня есть подозрение, что этот рецепт требует useEffect?

Ответы [ 2 ]

1 голос
/ 30 апреля 2020

В вашем компоненте сообщения используйте useEffect и слушайте messages.

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

Чтобы закрыть снэк-бар, вам нужно либо предоставить действие проп или 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>
        }
      />

Рабочая копия вашего кода находится здесь

0 голосов
/ 30 апреля 2020

На ум приходят два быстрых решения:

{
  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}
/>}
...