React中兄弟组件通信

3,844 阅读1分钟

业务场景:有A和B两个表格,互为兄弟组件,当A中某个事件调用完成之后需要触发B表格中的更新。

解决办法:使用发布-订阅模式,在A表格中订阅事件,等B表格中发布后通知它

代码实现:

export class SubscriptionPublish {
  private eventMap: Record<string, ((params: any) => any)[]>;
​
  constructor() {
    this.eventMap = {};
  }
​
  /**
   * 订阅函数
   * @param key 订阅事件Key值
   * @param handler 订阅事件
   */
  on(key: string, handler: (params: any) => any) {
    if (!this.eventMap[key]) {
      this.eventMap[key] = [];
    }
    this.eventMap[key].push(handler);
  }
​
  /**
   * 发布函数
   * @param key 订阅事件Key值
   * @param params 要发步到订阅事件中的参数
   */
  emit(key: string, params?: any) {
    if (this.eventMap[key]) {
      this.eventMap[key].forEach((handler) => {
        handler(params);
      });
    }
  }
​
  /**
   * 销毁函数
   * @param key
   * @param handler
   */
  remove(key: string, handler: (params: any) => any) {
    if (this.eventMap[key]) {
      // 如果该队列存在,先找到要删除函数的位置,然后剔除
      const res = this.eventMap[key].indexOf(handler);
      res !== -1 && this.eventMap[key].splice(res, 1);
    }
  }
}
​
// 创建一个全局实例
const defaultEvent = new SubscriptionPublish();
​
export default defaultEvent;
​

代码使用:我们在写完发布-订阅类的代码之后在里面创建一个实例,用作全局使用

  • A表格
const ApiTable: FC= () => {
  
  // ...省略其他业务代码
​
  // 刷新列表方法
  const loadApi = () => {
    table.reload();
  };
​
  useEffect(() => {
    // 订阅刷新方法
    defaultEvent.on('loadApi', loadApi);
    return () => {
      // 组件销毁时,销毁订阅函数
      defaultEvent.remove('loadApi', loadApi);
    };
  }, []);
​
​
  return (
    <>
      // ...业务代码
    </>
  );
};
​
export default ApiTable;
  • B表格
const Index: FC = () => {
​
  // ...省略其他业务代码
  
  // 这里是要触发发布的地方
  const handleSubmit = useCallback(async () => {
    
    // ...省略其他逻辑处理
    
    // 发布后,订阅函数调用
    defaultEvent.emit('loadApi');
  }, []);
​
  return (
    // ...业务代码
  );
};
​
export default Index;

发布-订阅模式专门用于解决兄弟组件间通信的问题,不局限于 React ,其他的地方原理是一样的,同样可以解决类似问题的还有观察者模式。我这里只是针对于我这样的业务场景下写的