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