• react 实现监听逻辑


    需求:

    • 在一个页面下有多个子tab
    • 在某些tab 下,或者父节点的数据更新的时候,其他子tab 或者父节点也要同步更新

    进程:

    • 正常情况下会把所有用到的数据都移动到父节点,修改行为也都放在父节点
    • 但如果这样的话父节点的数据会非常的多,而且有可能只是某两个子节点的数据需要更新,这就很麻烦
    • 换一个思路,所有的数据都放在各自子节点但是,在某个变化发生的时候,触发一下更新逻辑
    • 那又回到之前的那个问题了,需要每一个子节点都传入对应的触发函数
    • 再换一个逻辑,增加一个全局的hook 并绑定上对应的事件,在你想要触发更新的时候调用一下这个hook 行为,如果有绑定的事件的话,就会触发对应事件
    //eventhook
    type eventName = string | Symbol
    
    const eventMap = new Map<eventName, Array<Function>>()
    
    const addListenerByName = (name: eventName, func: Function) => {
      if (typeof func !== 'function') {
        return ;
      }
      const listeners = eventMap.get(name) || []
      if (!listeners.includes(func)) {
        eventMap.set(name, [...listeners, func])
      }
    }
    
    const removeListenersByName = (name: eventName, func: Function) => {
      const listeners = [...(eventMap.get(name) || [])]
      eventMap.set(name, listeners.filter(f => f !== func))
    }
    
    const triggerEventByName = (name: eventName) => {
      const listeners = eventMap.get(name) || []
      listeners.forEach(f => f())
    }
    
    type useEventReturn = {
      addListener: (func: Function) => () => void, // 调用返回的Function会remove监听
      removeListeners: (func: Function) => void,
      triggerEvent: () => void,
    }
    /**
     * 记得清除副作用
     * @param evenetName
     * @returns
     */
    export const useEvent = (name: eventName = '@@init'): useEventReturn => {
      return {
        addListener: func => {
          addListenerByName(name, func)
          return () => removeListenersByName(name, func);
        },
        removeListeners: func => removeListenersByName(name, func),
        triggerEvent: () => triggerEventByName(name),
      };
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 使用的时候 export 一个固定的名字 export const UPDATEUSERDATAEVENTNAME = Symbol('event_name')
    • use 这个hook const { addListener } = useEvent(UPDATEUSERDATAEVENTNAME)
    • 在需要被监听的地方在初始化的时候加入对应的监听逻辑
    useEffect(() => addListener(() => actionRef.current?.reload()), [])
    
    • 1
    • 在需要触发这个监听逻辑的地方加入const { triggerEvent } = useEvent(UPDATEUSERDATAEVENTNAME)
    • 并触发这个监听
    useEffect(() => {
        triggerEvent()
      }, [userId] )
    
    • 1
    • 2
    • 3
    • 这个做法的好处是就不需要往子组建传一堆东西了,而且也做到了更好的解耦

    拓展

    • 在使用这个方法的时候需要一个全局唯一的名字所以用到了 Symbol
    • Symbol是一个绝对唯一的常亮,极端的例子 Symbol(“test”) != Symbol(“test”)
  • 相关阅读:
    如何添加cookie
    Java Spring-AOP动态代理-JDK和CGlib实现
    Spark Structured Streaming 2021年最新进展的总结
    ESXI7.0.0升级到ESXI7.0.3
    MySQL read 查询语句8 主键 外键
    一文搞懂drag&drop浏览器拖放功能的实现
    java-net-php-python-jsp学生会人事管理信息系统计算机毕业设计程序
    使用setuptools构建python包
    食品饮料行业渠道商管理系统解决方案:实现渠道数字化营销布局
    Java基础—接口Lock
  • 原文地址:https://blog.csdn.net/weitao_11/article/details/132718088