基于React编写一个全局Toast的示例代码
作者:卸任
前言
前些日子在做项目的时候,需要封装一个Toast
组件。我想起之前用过的库,只要在入口文件中引入就可以在全局中使用,还是很方便的,借这次机会也来实现一下。说起来也算是forwardRef
、useImperativeHanle
和useContext
的实际使用。
- 第一种,使用
forwardRef
和useImperativeHanle
一个是像react-toastify
库一样使用,在入口处放置ToastContainer
,然后在代码中任意地方使用toast("Wow so easy!")
都有提示
import React from 'react'; import { ToastContainer, toast } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; function App(){ const notify = () => toast("Wow so easy!"); return ( <div> <button onClick={notify}>Notify!</button> <ToastContainer /> </div> ); }
- 第二种,使用
useContext
在入口处放置ToastProvider
,然后在代码中任意地方使用 const { show } = useToast()
都有提示。忘记什么库了。
文中就用antd
的message
来模拟一下我们自己写的Toast
组件。
正文
我们先来了解一下forwardRef
、useImperativeHanle
和useContext
的基本使用。
forwardRef
和 useImperativeHandle
的基本使用
forwardRef
和 useImperativeHandle
,它们通常一起使用,以便在父组件中暴露子组件的特定方法或属性。
forwardRef
,它允许你将父组件的ref
转发到子组件中的某个 DOM 节点或其他 React 组件。这样,父组件就可以访问子组件的引用,并直接操作它。
useImperativeHandle
是一个自定义 Hook,它允许你自定义通过 forwardRef
暴露给父组件的 ref
值。你可以指定哪些方法
或属性
被暴露,而不是直接暴露整个 DOM 节点或组件实例。
下面是一个简单的例子
import React, { forwardRef, useImperativeHandle, useRef } from 'react'; const ChildComponent = forwardRef((props, ref) => { const inputRef = useRef(null); useImperativeHandle(ref, () => ({ focus: () => { inputRef.current.focus(); }, })); return <input ref={inputRef} {...props} />; }); const ParentComponent = () => { const childRef = useRef(null); const handleClick = () => { childRef.current.focus(); }; return ( <div> <ChildComponent ref={childRef} /> <button onClick={handleClick}>Focus Child Input</button> </div> ); }; export default ParentComponent;
使用forwardRef和useImperativeHanle封装全局Toast
封装组件
import React, { createRef, forwardRef, useImperativeHandle } from 'react'; import { Button, message } from 'antd'; const Toast = forwardRef((props, ref) => { const [messageApi, contextHolder] = message.useMessage(); useImperativeHandle(ref, () => ({ show: (msg: string) => { messageApi.info(msg); } })); return <> {contextHolder} </> }) const ToastRef = createRef<{ show: (msg: string) => {} }>(); export const ToastContain = () => { return <Toast ref={ToastRef} /> } export const showToast = (msg: string) => { if (ToastRef.current) { ToastRef.current.show(msg) } };
在入口中引入
import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; import router from '@/router/index' import reportWebVitals from './reportWebVitals'; import { RouterProvider } from 'react-router-dom'; import ErrorBoundary from './ErrorBoundary'; import { ToastContain } from './components/Toast'; const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement ); root.render( <React.StrictMode> <ToastContain /> <RouterProvider router={router} fallbackElement={<div>准备中</div>} /> </React.StrictMode> ); reportWebVitals();
然后就可以在全局中使用 showToast
方法了
import React from 'react'; import { showToast } from '../../../components/Toast'; export default function Index() { return <> <div onClick={() => { showToast('sadasds') }} > 提示弹窗 </div> </> }
useContext的基本使用
useContext
用于访问组件树中某个层级上定义的 Context
。Context
提供了一种在组件之间共享值的方式,而不必通过组件树的每个层级显式传递 props
。
- 创建 Context
首先,你需要创建一个 Context
对象。这可以通过调用 React.createContext
来完成。你还可以为默认值提供一个参数,如果 Context
的 Provider
没有在组件树中找到,将使用这个默认值。
import React from 'react'; const MyContext = React.createContext('defaultValue');
- 提供 Context
你需要在组件树中的某个地方提供这个 Context
。这通常在组件的顶层完成,通过使用 MyContext.Provider
组件,并传递一个 value
prop
import React from 'react'; import MyComponent from './MyComponent'; import { MyContext } from './MyContext'; function App() { return ( <MyContext.Provider value="Hello from Context"> <MyComponent /> </MyContext.Provider> ); } export default App;
- 使用
useContext
在需要访问 Context
的组件中,你可以使用 useContext
Hook 来获取 Context
的当前值
import React, { useContext } from 'react'; import { MyContext } from './MyContext'; function MyComponent() { const contextValue = useContext(MyContext); return <p>Context value: {contextValue}</p>; } export default MyComponent;
使用useContext来封装全局Toast
封装组件
import React, { createContext, useCallback, useContext, useState } from 'react'; import { Button, message } from 'antd'; const ToastContext = createContext<any>(null); export const ToastProvider = ({ children }: any) => { const [messageApi, contextHolder] = message.useMessage(); const show = useCallback((msg: string) => { messageApi.info(msg); }, [messageApi]); return ( <ToastContext.Provider value={{ show }}> {children} {contextHolder} </ToastContext.Provider> ); }; export const useToast = () => { const context = useContext(ToastContext); return context; };
在入口处使用
import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; import router from '@/router/index' import reportWebVitals from './reportWebVitals'; import { RouterProvider } from 'react-router-dom'; import ErrorBoundary from './ErrorBoundary'; import { ToastProvider } from './components/ToastOne'; const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement ); root.render( <React.StrictMode> <ToastProvider> <RouterProvider router={router} fallbackElement={<div>准备中</div>} /> </ToastProvider> </React.StrictMode> );
然后就可以通过useToast
在全局中使用了
import React from 'react'; import { useToast } from '../../../components/ToastOne'; export default function Index() { const { show } = useToast() return <> <div onClick={() => { show('guiyu') }} > 点击提示 </div> </> }
结尾
以上就是基于React编写一个全局Toast的示例代码的详细内容,更多关于React编写全局Toast的资料请关注脚本之家其它相关文章!