0.0.1 • Published 10 months ago
react-easybus v0.0.1
react-easybus
简洁、高效的实现 react 跨模块通信,数据共享。
特点
- ✔ 设计简单
- ✔ 功能完整
- ✔ 性能强劲
- ✔ 解耦通信
- ✔ 开箱即用
- ✔ 函数组件 hooks 最强搭档
- ✔ 完美支持 typescript 类型检测
安装
npm install react-easybus
场景
- 页面级组件通信(PageBus)
- 应用级组件通信(AppBus)
- 可复用组件通信(ComponentBus)
页面级组件通信(PageBus)
单页面应用一般是通过切换路由的方式调用 JS 重新渲染 DOM 的方式实现的页面切换,一个页面的功能会有很多组件组成,这些组件通常会有一定的数据通信,比如父组件通过 props 把值传递给子组件,子组件调用一个方法更新父组件的状态,兄弟组件之间的通信等。
跨模块状态使用及更新(代替 props)
- $bus.useState(~) 返回依赖状态
- $bus.setState(~) 更新状态
通过以上 2 个 api 即可实现跨任意层级的模块状态的使用和更新
声明通信桥对象$bus.ts
import { PageBus } from 'react-easybus';
const $bus = PageBus<{
name: string;
}>.create();
export default $bus;
页面入口模块Page.tsx
import React from 'react';
import Mod1 from './Mod1';
import Mod2 from './Mod2';
import $bus from './$bus';
function Page() {
// 在入口模块安装并初始化状态
$bus.initState({
name: 'name',
});
return (
<>
<Mod1 />
<Mod2 />
</>
);
}
子模块Mod1.tsx
import $bus from './$bus';
export default function Mod1() {
// 从$bus中引入name状态
const { name } = $bus.useState(['name']);
return <div>名称是:{name}</div>;
}
子模块Mod2.tsx
import Mod3 from './Mod3';
export default function Mod2() {
return <Mod3 />;
}
孙子模块Mod3.tsx
import $bus from './$bus';
export default function Mod3() {
// 从$bus中引入name状态,也可以使用 const { name } = $bus.resState; 来导入并监听状态
const { name } = $bus.useState(['name']);
return (
<>
<div>名称是:{name}</div>
<button
onClick={() => {
// 更新name状态,Mod1,Mod3都会更新
$bus.setState({
name: 'newName',
});
}}
>
更新名称
</button>
</>
);
}
跨模块通信 1
声明通信桥对象$bus.ts
import { PageBus } from 'react-easybus';
const $bus = PageBus.create(
class MyBus extends PageBus {
setName: (name: string) => void;
}
);
export default $bus;
入口模块 Page.tsx
import React from 'react';
import Mod1 from './Mod1';
import Mod2 from './Mod2';
import $bus from './$bus';
function Page() {
$bus.initState();
return (
<>
<Mod1 />
<Mod2 />
</>
);
}
子模块Mod1.tsx
import $bus from './$bus';
export default function Mod1() {
const [value, setValue] = useState('');
$bus.setName = (value) => setValue(value);
return <div>Mod2输入的值是:{value}</div>;
}
子模块Mod2.tsx
import $bus from './$bus';
export default function Mod2() {
return (
<div>
<input
onChange={(e) => {
$bus.setName(e.target.value);
}}
/>
</div>
);
}
跨模块通信 2
- $bus.useMessager(cmd, callback) 监听消息
- $bus.callMessager(cmd, payload) 广播消息
通过以上 2 个 api 实现无耦合的跨模块通信
声明通信桥对象$bus.ts
import { createBridge, PageBus } from 'react-easybus';
const $bus = createBridge(
PageBus<{
setName: {
name: string;
};
}>
);
export default $bus;
入口模块 Page.tsx
import React from 'react';
import Mod1 from './Mod1';
import Mod2 from './Mod2';
import $bus from './$bus';
function Page() {
$bus.initState();
return (
<>
<Mod1 />
<Mod2 />
</>
);
}
子模块Mod1.tsx
import $bus from './$bus';
export default function Mod1() {
const [value, setValue] = useState('');
$bus.useMessager('setName', (payload) => {
setValue(payload.name);
});
return <div>Mod2输入的值是:{value}</div>;
}
子模块Mod2.tsx
import $bus from './$bus';
export default function Mod2() {
return (
<div>
<input
onChange={(e) => {
$bus.callMessager('setName', {
name: e.target.value,
});
}}
/>
</div>
);
}
一个完整的示例
PageBus(页面级状态管理)
$bus.ts (桥对象声明)
import { PageBus } from 'react-easybus';
// 签名可以省略,加了之后可以享受ts的各种好处
const $bus = PageBus.create(
class MyPageBus extends PageBus<
// 状态签名
{
name: string;
age: number;
},
// 消息签名
{
hello: {
message: string;
};
}
> {
// 方法签名
toggleTips: () => void;
}
);
export default $bus;
page.tsx 页面使用
import React, { memo, useState } from 'react';
import $bus from './$bus';
// 入口模块
export default memo(() => {
$bus.initState({
name: '张三',
age: 18,
});
return (
<div>
<Mod1 />
<Mod2 />
<Mod3 />
<Mod4 />
<Mod5 />
</div>
);
});
// 状态使用
const Mod1 = memo(() => {
const { age } = $bus.resState;
return <div>年龄:{age}</div>;
});
// 状态更新
const Mod2 = memo(() => {
return (
<div
onClick={() => {
// 直接调用update更新桥状态
$bus.setState((state) => {
state.age++;
});
}}
>
更新年龄
</div>
);
});
// 方法挂载
const Mod3 = memo(() => {
const [visible, setVisible] = useState(false);
// 挂载方法,其他模块可以通过$bus.toggleTips()完成跨模块通信
$bus.toggleTips = () => {
setVisible(!visible);
};
return <div style={{ display: visible ? '' : 'none' }}>tipsBox</div>;
});
// 方法调用
const Mod4 = memo(() => {
return (
<div>
<button
onClick={() => {
$bus.toggleTips();
}}
>
切换显示tips
</button>
</div>
);
});
// 消息监听
const Mod5 = memo(() => {
const [message, setMessage] = useState('');
$bus.useMessager('hello', (payload) => {
setMessage(payload.message);
});
return <div>接收的消息为:{message}</div>;
});
// 消息广播
const Mod6 = memo(() => {
return (
<div>
<button
onClick={() => {
$bus.callMessager('hello', {
message: String(Math.random()),
});
}}
>
广播消息
</button>
</div>
);
});
API
PageBus.create(MyPageBus)
创建局部桥对象$bus.initState(initalState:State)
安装并初始化桥对象状态$bus.useState(option:Array<keyof State> | (state:State) => any)
监听并返回状态中的值,当 option 为数组时,则返回状态在数组中的对应字段,假如 option 为函数,则使用函数返回值作为监听的数据$bus.setState(nextState: State | (state)=>state )
更新桥状态,假如是对象,则和原状态进行浅合并,假如是函数,则使用返回值替换原状态,假如函数无返回值,则可以通过直接操作 state 进行更新状态$bus.xxx = (...args) => any
挂载方法,允许其他模块通过$bus.xxx(...args)
的方式与当前模块进行通信$bus.useMessager(cmd, callback, delay?:number); $bus.callMessager(cmd, payload)
创建消息通信,允许不同模块创建消息监听,可以直接接受任何模块的广播消息并做出响应,广播消息允许发送参数payload
,假如存在delay
,那么广播的消息在相应的时间内进行合并处理
$bus.useState(~) 示例,通过 useState 进行状态精确监听,优化渲染性能
/// state = {name:'张三',age:18,info:{address:'浙江省'}}
// 方式1:返回name,age并且state.name和state.age发生变更时,都会触发函数render
const { name, age } = $bus.useState(['name', 'age']);
// 方式2:返回并监听state.info.address,仅在address的值发生变化时才触发函数render
const { address } = $bus.useState((state) => ({
address: state.info.address,
}));
AppBus(全局级状态管理)
全局应用状态管理会跨页面进行通信,主要用于一些全局状态比如用户信息,应用配置等的数据管理
$bus.ts 声明桥对象
import { AppBus } from 'react-easybus';
const $bus = AppBus.create(
class MyAppBus extends AppBus<
// 状态签名
{
name: string;
age: number;
},
// 消息签名
{
hello: {
message: string;
};
}
> {
toggleTips() {
// ...
}
},
{ name: '张三', age: 18 }
);
export default $bus;
全局桥对象不需要
$bus.initState(~)
,初始化状态在 create 的时候作为第二个参数传入,其他接口和PageBus
完全保持一致
完美结合 hooks
通过挂载Dispatcher
或者监听广播Messager
的方式,可以完美的与useState
结合进行模块状态控制,通信调用,消息模式可以解耦模块逻辑,不会出现调用不存在的方法导致脚本错误
结合 typescript
通过State
,Dispatcher
,Messager
定义签名,完全满足 typescript 的类型检测和自动提示
说明
更多示例见 node_modules/react-easybus/sample
使用模板见 node_modules/react-easybus/template
完整 API
- $bus.useState(~) 创建状态依赖并返回状态值
- $bus.setState(~) 更新状态
- $bus.xxx(~) 调用 dispatcher 方法,以继承的方式定义
- $bus.useMessager(~) 创建消息监听
- $bus.callMessager(~) 广播消息
- PageBus 页面桥类
- PageBus.create(~)
- $bus.initState(~) 安装桥对象
- AppBus 应用桥类
- AppBus.create(~)
- AppBusProvider 全局桥上下文
- ComponentBus 组件桥类
- ComponentBus.create(~)
- initState(~) 安装桥对象
- useBus(~) 使用桥对象
0.0.1
10 months ago