Socket
Socket
Sign inDemoInstall

@ctsx/bridge

Package Overview
Dependencies
4
Maintainers
1
Versions
2
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    @ctsx/bridge

react 状态管理


Version published
Weekly downloads
0
decreased by-100%
Maintainers
1
Install size
366 kB
Created
Weekly downloads
 

Readme

Source

@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 使用桥对象

Keywords

FAQs

Last updated on 31 Jan 2023

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc