在 React 和 Material-UI 中处理消息警报状态的惯用方法

Idiomatic way to handle Message Alerts state in React and Material-UI

我基本上是在使用 React 和 material UI 构建 Web 应用程序。我有一张注册表。

此注册表单成功提交后,应在页面顶部显示一条成功消息。

现在,我已经封锁了每个页面的顶部以显示 MyAlert 组件。我这样做是为了使我的网站更加一致。基本上只要有消息要显示给用户,它就会在那里呈现。

现在,问题是消息一旦显示,如果我在我的网站上导航,就无法将其关闭。

有人可以帮忙解释一下显示消息一次然后隐藏它的最佳方法是什么吗?基本上,一旦用户注册成功,就会显示一条成功消息。用户导航到新页面后,隐藏顶部的消息,直到需要显示新消息。

我想这是一个非常常见的设计模式,所以我在 React 知识方面一定缺少一些东西。即使是最佳实践设计模式,或如何处理它的链接也会受到赞赏。

我的玩具应用如下所示:

App.jsx

    import * as React from 'react'
    import { useState, useEffect } from 'react'
    import { BrowserRouter, Switch, Route } from 'react-router-dom'
    import { Link } from 'react-router-dom'

    import { Alert } from '@material-ui/lab'
    import MenuIcon from '@material-ui/icons/Menu'
    import {
        Button,
        AppBar,
        Toolbar,
        IconButton,
        Typography,
        makeStyles,
        Container,
    } from '@material-ui/core'

    const useStyles = makeStyles((theme) => ({
        root: {
            flexGrow: 1,
        },
        menuButton: {
            marginRight: theme.spacing(2),
        },
        title: {
            flexGrow: 1,
        },
    }))

    const Navbar = (props) => {
        const classes = useStyles()
        return (
            <div>
                <AppBar position="static">
                    <Toolbar>
                        <IconButton
                            edge="start"
                            className={classes.menuButton}
                            color="inherit"
                            aria-label="menu"
                        >
                            <MenuIcon />
                        </IconButton>
                        <Typography variant="h6" className={classes.title}>
                            <Button color="inherit" component={Link} to={'/'}>
                                My App
                            </Button>
                        </Typography>
                        <Button color="inherit" component={Link} to={'/register'}>
                            Register
                        </Button>
                    </Toolbar>
                </AppBar>
            </div>
        )
    }

    const Register = (props) => {
        const classes = useStyles()
        const { setShowAlert, setAlertMessage, setAlertSeverity } = props

        useEffect(() => {
            console.log('use effected')
        }, [])

        const handleRegistration = () => {
            setAlertMessage(
                'You have succesfully registered! Please check your email for a verification link.'
            )
            setAlertSeverity('success')
            setShowAlert(true)
        }

        return (
            <Container maxWidth="sm" align="center" className={classes.root}>
                This is some kind of form. I have redacted all input fields to
                illustrate the issue more clearly.<br></br>
                <Button
                    variant="contained"
                    color="primary"
                    onClick={handleRegistration}
                >
                    Register
                </Button>
            </Container>
        )
    }

    const MyAlert = (props) => {
        const { severity, message } = props
        return <Alert severity={severity}>{message}</Alert>
    }

    const App = () => {
        const [alertSeverity, setAlertSeverity] = useState('')
        const [alertMessage, setAlertMessage] = useState('')
        const [showAlert, setShowAlert] = useState(false)

        return (
            <BrowserRouter>
                <div className="app">
                    <Navbar />
                    <div>{showAlert ? 'true' : 'false'}</div>
                    {showAlert ? (
                        <MyAlert severity={alertSeverity} message={alertMessage} />
                    ) : (
                        ''
                    )}
                    <Switch>
                        <Route
                            path="/register"
                            render={(props) => (
                                <Register
                                    {...props}
                                    setShowAlert={setShowAlert}
                                    setAlertMessage={setAlertMessage}
                                    setAlertSeverity={setAlertSeverity}
                                />
                            )}
                        />
                    </Switch>
                </div>
            </BrowserRouter>
        )
    }

    export default App

index.jsx

import * as React from "react"
import { render } from "react-dom"
import App from './App';

render(<App />, document.getElementById("app"))

不就是使用setTimeout吗?呈现 MyAlert 时,显示它 5 秒,然后关闭。

首先,将其作为 prop 传递给您的组件(我还提出了一个略有不同的条件渲染):

            <BrowserRouter>
                <div className="app">
                    <Navbar />
                    <div>{showAlert ? 'true' : 'false'}</div>
                    {showAlert && 
                        <MyAlert severity={alertSeverity} message={alertMessage} setShowAlert = {setShowAlert}/> }
                    
                    <Switch>
                        <Route
                            path="/register"
                            render={(props) => (
                                <Register
                                    {...props}
                                    setShowAlert={setShowAlert}
                                    setAlertMessage={setAlertMessage}
                                    setAlertSeverity={setAlertSeverity}
                                />
                            )}
                        />
                    </Switch>
                </div>
            </BrowserRouter>

然后在您的 MyAlert 组件中,使用 useEffect 触发超时:

  const MyAlert = (props) => {
   useEffect(() => {
     const timeout = setTimeout(() => {
       props.setShowAlert(false);  // Disable your alert after 5 seconds
      }, 5000);

     return () => {
       clearTimeout(timeout); // Clears timer in case you close your alert somewhere else.
     }
   }, [])
}