NutUI React 在 Taro 中实现函数调用的方法
背景
在 NutUI React Taro 1.x 的实现中,由于微信小程序下不能动态插入标签,所以 NutUI React Taro 中的 Toast 组件采用的是标签方式的使用方法。
然而 Toast 标签的使用方式比较繁琐。此用法如下所示:
import React, {useState} from 'react'
import {Toast} from '@/packages/nutui.react.taro'
function Demo() {
const [showToast, setShowToast] = useState(false)
return (
<Toast
msg={'标签'}
visible={showToast}
onClose={() => {
setShowToast(false)
}}
/>
)
}
在这个例子中,需要通过增加 state 的方法,来控制 Toast 组件的 visible,从而实现 toast 展示或隐藏。现在仅仅是控制 Toast 的显示或隐藏,在实际的业务中,还需要控制 Toast 的类型,Toast 的 msg。这样就需要增加多个 state。而标签组件的使用方式在进行需要处理跨组件的通信。从而进一步增加 Toast 的使用难度。
能不能通过给 Toast 增加 show() 方法来控制 Toast 的展示?
function OtherComponent() {
return <Toast />
}
function Demo() {
return (
<Button onClick={() => Toast.show()}>Click me</Button>
)
}
实现
Toast.show 方法主要的责任是通知 Toast 调用 state 相关的处理逻辑,将 Toast 组件展示出来。在众多设计模式中,发布订阅模式提供了这类问题的解决模板。
在发布订阅模式中,我们使用一个中介者(事件总线)来管理发布者和订阅者之间的通信。示例如下:
class EventBus {
constructor() {
this.subscribers = {};
}
subscribe(event, callback) {
if (!this.subscribers[event]) {
this.subscribers[event] = [];
}
this.subscribers[event].push(callback);
}
publish(event, data) {
if (this.subscribers[event]) {
this.subscribers[event].forEach(callback => callback(data));
}
}
}
// 用法
const eventBus = new EventBus();
eventBus.subscribe("message", data => {
console.log(`Received message: ${data}`);
});
eventBus.publish("message", "Hello subscribers!");
Taro 提供了 Taro.Events,借助 Taro.EVents 可以实现发布订阅模式中的中介者(事件总线)。 我们先来看下 Taro.Events 的使用方法,以便直观的对照发布订阅模式的 Demos。下面代码来自 Taro 文档。
import Taro, { Events } from '@tarojs/taro'
const events = new Events()
// 监听一个事件,接受参数
events.on('eventName', (arg) => {
// doSth
})
// 监听同个事件,同时绑定多个 handler
events.on('eventName', handler1)
events.on('eventName', handler2)
events.on('eventName', handler3)
// 触发一个事件,传参
events.trigger('eventName', arg)
// 触发事件,传入多个参数
events.trigger('eventName', arg1, arg2, ...)
// 取消监听一个事件
events.off('eventName')
// 取消监听一个事件某个 handler
events.off('eventName', handler1)
// 取消监听所有事件
events.off()
在 Toast 组件的实现中,消息的名称通过 router + id 的方式处理。而且为了便于使用,将 Taro.Events 封装成了名为 useCustomEvent 的 hook。
export const customEvents = new Events()
function useCustomEvent(selector, cb) {
useEffect(() => {
customEvents.on(path, cb)
return () => {
customEvents.off(path)
}
}, [])
}
这样 Toast 组件中可以直接通过 useCustomEvent 订阅事件的处理逻辑
useCustomEvent(
porps.id,
({ status }) => {
if (status) {
show()
} else {
hide()
}
}
)
Toast.show 方法可以通过 customEvents 事件总线发布消息。
function show(selector) {
const path = useCustomEventsPath(selector)
customEvents.trigger(path, { status: true })
}
以上是 Toast 实现函数调用的演示,代码细节可以查看 NutUI React 仓库。