前言
前些日子在做项目的时候,需要封装一个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的资料请关注代码网其它相关文章!
发表评论