发布订阅模式应用

451 阅读1分钟

业务背景

  • h5内嵌iframe
  • 通过postMessage与web通信
  • 其中一个通信约定是:h5页面在初始化;或者任意子组件销毁;或者高度发生变化的时候时候都要向web,send 当前h5下所有组件的相关信息

代码实现

  • BaseComponent 用于包裹所有需要与web进行通信的组件
  • globalStore 封装了通信函数,此处不做展开
//主要代码
import baseStore from './store';

interface Props {
  name: string
  children: React.ReactNode;
}
function BaseComponent(props: Props): JSX.Element{
  const currentComponent = useRef<any>(null);
  
  useEffect(()=>{
    if(!currentComponent.current) return;
    const key = Symbol();
    baseStore.register(key, currentComponent.current, props.name);
    return ()=>{
      baseStore.unRegister(key);//组件销毁时,告知web,当前组件销毁,并重新publish所有组件的最新信息
    }
  }, []);

  useEffect(()=>{
    if(!currentComponent.current) return;
    baseStore.publish();
    // 做了一个骨架屏的占位,根据接口重新渲染会产生高度变化;
    //或者web的交互导致h5组件发生变化时都要重新发送所有组件的最新信息给web
  }, [currentComponent.current ? currentComponent.current.offsetHeight : 0]);

  const { currentComponentName } = globalStore
  const isCurrentComponent = props.name === currentComponentName
  return(
    <View
      className={'base-component-wrap'}
       ref={currentComponent} 
    >
      {props.children}
    </View>
  ) 

}

export default observer(BaseComponent);

  • baseStore 做组件的依赖收集工作
class Store {
    refList: Map<Symbol, any> = new Map([]);
    register = (key: Symbol, ref: any, name: string)=>{
        this.refList.set(key, {
            ref, name
        });
        this.publish();
    }
    unRegister = (key:Symbol)=>{
        this.refList.delete(key);
        this.publish();
    }
    publish = ()=>{
        this.refList.forEach(({ref, name})=>{
            globalStore.sendComponentInfo(name, ref);
        })
    }
}
export default new Store();

小结

代码不难 ,但每一次看似无用的知识储备,被落地在项目里,会有莫名的成就感,时间很仓促,代码总体目前还不够优雅

最后,码字不易 ,如果你有收获,点👍给个鼓励