如何实现material-ui Snackbar为全局函数?

问题描述 投票:0回答:4

我正在使用 Material-ui Snackbar 创建我的 React 应用程序。 在我的项目中,我有很多组件,并且不想在每个组件中插入 。 有没有办法创建显示小吃栏的函数,然后在每个组件中导入并使用这个函数?

类似:

从 'SnackbarUtils' 导入 showSnackbar;

showSnackbar('成功消息');

javascript reactjs notifications material-ui snackbar
4个回答
21
投票

你必须以反应的方式来做。您可以通过创建高阶组件来实现这一点。

  1. 创建一个 HOC,返回 snackbar 组件以及wrappedComponent
  2. 在该 HOC 中创建一个函数,它接受消息、严重性(如果您像我一样使用 Alert)、持续时间并设置设置为零食栏props 的适当状态。并将该函数作为 prop 传递给wrappedComponent。
  3. 最后在您想要显示小吃栏的任何地方导入此 HOC,将您的组件传递到其中,并在您想要显示小吃栏的事件处理程序中从 prop (this.prop.functionName('Hello There!')) 调用 HOC 函数小吃栏并传递消息。

看看这个。 https://stackblitz.com/edit/snackbar-hoc?file=src/SnackbarHOC.js


17
投票

将其扩展为Hook,然后调用一次即可使用带效果的状态来显示:

import { useSnackbar } from 'notistack';
import IconButton from "@mui/material/IconButton";
import CloseIcon from "@mui/material/SvgIcon/SvgIcon";
import React, {Fragment, useEffect, useState} from "react";


const useNotification = () => {
    const [conf, setConf] = useState({});
    const { enqueueSnackbar, closeSnackbar } = useSnackbar();
    const action = key => (
        <Fragment>
            <IconButton onClick={() => { closeSnackbar(key) }}>
                <CloseIcon />
            </IconButton>
        </Fragment>
    );
    useEffect(()=>{
        if(conf?.msg){
            let variant = 'info';
            if(conf.variant){
                variant = conf.variant;
            }
            enqueueSnackbar(conf.msg, {
                variant: variant,
                autoHideDuration: 5000,
                action
            });
        }
    },[conf]);
    return [conf, setConf];
};

export default useNotification;

然后就可以使用它了:

const [msg, sendNotification] = useNotification();

sendNotification({msg: 'yourmessage', variant: 'error/info.....'})

1
投票

这里是使用 Redux、Material-ui 和 MUI Snackbar 的完整工作示例的示例代码

import { random } from 'lodash'
import { Action } from 'redux'
import actionCreatorFactory, { isType } from 'typescript-fsa'

const actionCreator = actionCreatorFactory()

export type Notification = {
  message: string
}

export type NotificationStore = Notification & {
  messageId: number
}

export const sendNewNotification =
  actionCreator<Notification>('NEW_NOTIFICATION')

const defaultState: NotificationStore = { message: '', messageId: 1 }

const reducer = (
  state: NotificationStore = defaultState,
  action: Action
): NotificationStore => {
  if (isType(action, sendNewNotification)) {
    const {
      payload: { message }
    } = action
    return { message, messageId: random(0, 200000) }
  }

  return state
}

export default reducer





// useNotification to get state from Redux, you can include them into same file if you prefer

import { NotificationStore } from './notification'

export function useNotification(): NotificationStore {
  return useSelector<NotificationStore>(
    (state) => state.notification
  )
}


// Notification React-component - Notification.tsx

import React, { useState } from 'react'

import Button from '@mui/material/Button'
import Snackbar from '@mui/material/Snackbar'
import IconButton from '@mui/material/IconButton'
import CloseIcon from '@mui/icons-material/Close'

type Props = {
  message: string
}

export function Notification({ message }: Props): JSX.Element | null {
  const [notiOpen, setNotiOpen] = useState(true)

  if (!message) {
    return null
  }

  return (
    <Snackbar
      anchorOrigin={{
        vertical: 'bottom',
        horizontal: 'left'
      }}
      open={notiOpen}
      autoHideDuration={10000}
      onClose={() => setNotiOpen(false)}
      message={message}
      action={
        <React.Fragment>
          <Button
            color="secondary"
            size="small"
            onClick={() => setNotiOpen(false)}
          >
            Close
          </Button>
          <IconButton
            size="small"
            aria-label="close"
            color="inherit"
            onClick={() => setNotiOpen(false)}
          >
            <CloseIcon fontSize="small" />
          </IconButton>
        </React.Fragment>
      }
    />
  )
}


// Main App.tsx to run my application

import { Notification } from "./Notification.tsx"
import { useDispatch } from 'react-redux'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'

const App: React.FC<AppProps> = () => {
  const dispatch = useDispatch()
  const { message, messageId } = useNotification()

  return (
    <ThemeProvider theme={appTheme}>

      <Router>
        <Switch>
          <Route path="/public/:projectId" component={ProjectPage} />
          <Route path="/login" component={LoginPage} />
          <Route render={() => <PageNotFound />} />
        </Switch>
      </Router>
      <Notification key={messageId} message={message} />
    </ThemeProvider>
  )
}

export default App






// Usage of hook in application - FileSomething.tsx

import { useDispatch } from 'react-redux'
import { useEffect } from 'react'
import { sendNewNotification } from 'src/redux/notification'

export function FileSomething(): JSX.Element {
  
   function sendNotification() {
    dispatch(
      sendNewNotification({
        message: 'Hey, im a notification'
      })
    )
  }

  useEffect(() => {
    sendNotification()
  }, [])

  return (
    <div>Component doing something</div>
  )
}

0
投票

我建议使用

notistack
- 它会为您处理状态,并且可以通过单个实例化跨组件使用:https://github.com/iamhosseindhv/notistack

MUI 文档中也提到了:https://mui.com/material-ui/react-snackbar/#notistack

© www.soinside.com 2019 - 2024. All rights reserved.