likes
comments
collection
share

React & MUI 封装 Alert 消息组件

作者站长头像
站长
· 阅读数 33

问题:最近在写 React CMS 项目时,发现 Material-UI 的消息提示组件 Alert 组件需要与 Snackbar 组件结合使用,在每个界面进行重复的代码编写;另一种情况是在封装 request 网络请求时,无法像 React 函数组件一样引入 Alert 组件,从而实现报告网络请求响应是否成功的功能。

Material-UI 的消息提示组件是 , 没有主动提示的能力,属于被动组件,需要在页面中嵌入,然后通过属性 open 的true/false 进行控制。

解决办法:自定义封装组件 message.js

环境准备:react@18.2.0 @mui/material@5.8.6 react-dom@18.2.0

Tips: React 18 不再支持 ReactDOM.render,否则控制台会抛出:Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. 的警告信息,不会影响程序正常的运行。

建议使用 createRoot

Snackbar API

open: Boolean 类型 true/false,控制消息框关闭

autoHideDuration: Number,控制显示时间

anchorOrigin: Object, 控制消息体显示位置

onClose: 主动关闭事件

1、封装一个 Message 组件

import { useState } from 'react';
// material-ui
import { Snackbar, Alert } from '@mui/material';

function Message(props) {
    const { content, duration, type } = {...props};
    // 开关控制:默认true,调用时会直接打开
    const [open, setOpen] = useState(true);
    // 关闭消息提示
    const handleClose = (event, reason) => {
        setOpen(false);
    };
    return (
        <Snackbar open={open} autoHideDuration={duration} anchorOrigin={{ vertical: 'top', horizontal: 'center' }} onClose={handleClose}>
            <Alert severity={type} variant="standard">
                {content}
            </Alert>
        </Snackbar>
    );
}

2、引用 Message,定义 message 的主动事件

import { createRoot } from 'react-dom/client';

const message = {
    dom: null,
    success({ content, duration = 1500 }) {
        // 创建一个dom
        this.dom = document.createElement('div');
        // 定义组件,
        const JSXdom = <Message content={content} duration={duration} type="success"></Message>;
        // 渲染DOM
        createRoot(this.dom).render(JSXdom);
        // 置入到body节点下
        document.body.appendChild(this.dom);
    },
    error({ content, duration }) {
        this.dom = document.createElement('div');
        const JSXdom = <Message content={content} duration={duration} type="error"></Message>;
        createRoot(this.dom).render(JSXdom);
        document.body.appendChild(this.dom);
    },
    warning({ content, duration }) {
        this.dom = document.createElement('div');
        const JSXdom = <Message content={content} duration={duration} type="warning"></Message>;
        createRoot(this.dom).render(JSXdom);
        document.body.appendChild(this.dom);
    },
    info({ content, duration }) {
        this.dom = document.createElement('div');
        const JSXdom = <Message content={content} duration={duration} type="warning"></Message>;
        createRoot(this.dom).render(JSXdom);
        document.body.appendChild(this.dom);
    }
};

export default message;

3、引用

根据不同的提示传入不同的参数,达到效果:

if (status === 200) {
    message.success({content: '请求成功!',  duration: 1500})
}

if (status === 404) {
    // duration 默认为 1500
    message.error({content: '页面未找到!'})
    return null
}

应用在实际的 request 请求中:

const handleEditPublished = (row) => {
    updatePublished(row.id, row.published)
        .then((res) => {
        if (res.code === 200) {
            message.success({ content: res.msg });
        } else {
            message.error({ content: res.msg });
        }
    })
        .catch(() => {
        message.error({ content: '请求失败' });
    });
};