React 自定义 Hook 实现滚动事件监听

望舒的头像
望舒
标签:
reactjs自定义hooks滚动事件

在 React 开发中,常常需要监听滚动事件,比如:

  • 滚动到顶部/底部时触发回调
  • 判断元素是否可滚动
  • 滚动时触发动画或加载数据

本篇文章将带来一个 高性能且易用的 useScroll 自定义 Hook,并结合 lodash 的防抖(debounce)优化性能,同时详细解析每个步骤和原理。


📦 Hook 功能简介

useScroll 支持以下功能:

  • 监听 scroll 事件
  • 滚动到顶部或底部时触发回调
  • 支持元素或 document 滚动
  • 自动检测元素是否可滚动
  • 可配置防抖时间、偏移量等

✏️ 完整代码

下面是 完整代码

复制
import { useState, useEffect, useRef, useCallback } from "react"
import debounce from "lodash/debounce"

interface UseScrollProps {
  ele: React.RefObject<HTMLElement | HTMLBodyElement>
  onNonExistScroll?: () => boolean
  onScroll?: (e: Event) => void
  onScrollToBottom?: () => void
  onScrollToTop?: () => void
  debounceTimeOut?: number
  debounceOptions?: { leading?: boolean; trailing?: boolean }
  offsetValue?: number
}

export function useScroll({
  ele,
  onNonExistScroll,
  onScroll,
  onScrollToBottom,
  onScrollToTop,
  debounceTimeOut = 100,
  debounceOptions,
  offsetValue = 10,
}: UseScrollProps) {
  const timerRef = useRef<number>()
  const testScrollExistCount = useRef(0)
  const [existScroll, setExistScroll] = useState(false)

  const handleOnScrollToBottom = useCallback(() => {
    onScrollToBottom && onScrollToBottom()
  }, [onScrollToBottom])

  const handleOnScrollToTop = useCallback(() => {
    onScrollToTop && onScrollToTop()
  }, [onScrollToTop])

  const handleOnScroll = useCallback(
    debounce((e: Event) => {
      if (!e.target || !ele.current) return

      const target = ele.current instanceof HTMLBodyElement
        ? document.scrollingElement as HTMLElement
        : e.target as HTMLElement

      onScroll && onScroll(e)

      const { clientHeight, scrollTop, scrollHeight } = target

      if (scrollHeight - scrollTop <= clientHeight + offsetValue) {
        handleOnScrollToBottom()
      }
      if (scrollTop === 0) {
        handleOnScrollToTop()
      }
    }, debounceTimeOut, debounceOptions),
    [debounceTimeOut, debounceOptions, ele, offsetValue, handleOnScrollToBottom, handleOnScrollToTop, onScroll]
  )

  const testScrollExist = useCallback(() => {
    if (!ele.current) return

    testScrollExistCount.current += 1
    if (testScrollExistCount.current > 5 && timerRef.current) {
      clearInterval(timerRef.current)
    }

    let newExistScroll = false

    if (ele.current instanceof HTMLBodyElement) {
      newExistScroll = ele.current.scrollHeight > window.innerHeight
    } else {
      const { clientHeight, scrollHeight } = ele.current
      newExistScroll = scrollHeight > clientHeight
    }

    if (newExistScroll) {
      timerRef.current && clearInterval(timerRef.current)
    } else {
      if (onNonExistScroll) {
        const stop = onNonExistScroll()
        if (stop) timerRef.current && clearInterval(timerRef.current)
      }
    }

    setExistScroll(newExistScroll)
  }, [ele, onNonExistScroll])

  useEffect(() => {
    if (ele.current) {
      timerRef.current = window.setInterval(testScrollExist, 1000)
    }
    return () => {
      timerRef.current && clearInterval(timerRef.current)
    }
  }, [ele, testScrollExist])

  useEffect(() => {
    const target = ele.current

    if (!target) return

    if (target instanceof HTMLBodyElement) {
      document.addEventListener("scroll", handleOnScroll)
    } else {
      target.addEventListener("scroll", handleOnScroll)
    }

    return () => {
      if (target instanceof HTMLBodyElement) {
        document.removeEventListener("scroll", handleOnScroll)
      } else {
        target.removeEventListener("scroll", handleOnScroll)
      }
    }
  }, [ele, handleOnScroll])

  return { existScroll }
}

🧠 核心思路解析

1. 判断滚动目标 支持监听 document<body>)或具体 DOM 元素。

2. 防抖 使用 lodash/debounce 防止滚动事件高频触发,提高性能。

3. 判断滚动是否到达底部/顶部 根据:

  • scrollHeight - scrollTop <= clientHeight + offsetValue (底部)
  • scrollTop === 0 (顶部)

4. 判断元素是否可滚动 根据 scrollHeight > clientHeight(元素)或 scrollHeight > window.innerHeight(文档)。


🧩 使用示例

复制
const scrollRef = useRef<HTMLDivElement>(null)

const { existScroll } = useScroll({
  ele: scrollRef,
  onScroll: () => console.log("Scrolling..."),
  onScrollToBottom: () => console.log("Reached bottom!"),
  onScrollToTop: () => console.log("Reached top!"),
  debounceTimeOut: 200,
})

🌱 总结

通过一个简单的自定义 Hook,就能轻松实现滚动监听、到顶/底检测、滚动存在性检测等常见需求。再配合防抖处理,就能让滚动监听既高效又易用。

作者:https://blog.xn--rpv331d.com/望舒

链接:https://blog.xn--rpv331d.com/望舒/blog/83

转载注意保留文章出处...

‌​‌‌‌‌​‌​‌​​‌​‌‌‌‌‌‌‌‌‌‌​‌​‌‌​‌‌‌​‌‌‌​‌‌​‌​‌‌​‌‌‌‌‌‌‌​‌‌​‌‌‌‌‌‌‌‌‌‌‌‌​​‌​‌​​‌​‌‌‌‌‌‌‌​‌‌​‌​‌‌‌‌‌‌‌‌‌‌‌‌‌​‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌‌​‌​‌​​‌‌‌‌‌​‌‌‌​‌‌​‌‌‌‌​‌‌‌‌‌‌‌​​‌​‌​​‌‌‌‌‌‌‌‌‌​‌‌​‌​​‌​‌‌‌​‌‌‌​​‌​‌​​‌‌‌‌‌‌‌‌‌‌‌‌​‌​‌‌​‌‌‌​‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌‌‌‌​‌​‌‌​‌​‌‌‌‌​‌​‌​‌‌​​​​​​‌‌​‌​‌​‌‌‌‌​​‌‌‌‌​​​​​‌​​‌​‌‌​​​‌‌​‌‌‌‌​‌​‌​​‌​‌‌‌‌‌‌‌​‌‌​‌​‌‌‌‌‌‌​‌‌‌​‌‌​‌​‌‌​‌‌‌‌‌‌‌​​‌​‌​‌‌​‌‌‌‌‌‌‌‌‌‌​‌‌‌‌​‌‌‌‌‌‌‌​‌‌​‌​​‌‌‌‌‌‌‌‌‌​‌‌​‌‌​‌​‌‌‌​‌‌‌‌​‌​‌​​‌‌‌‌‌​‌‌‌​‌‌​‌‌‌‌​‌‌‌‌‌‌‌​​‌​‌​‌‌​‌‌‌‌‌‌‌‌‌‌​‌​​‌​‌‌‌‌‌‌‌‌‌‌​‌​​‌​‌‌‌‌‌‌‌‌‌‌​‌​‌‌​‌‌‌‌‌‌‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌‌​‌​‌‌‌‌​‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌​‌‌​‌‌‌‌​‌‌‌‌‌‌‌​​‌​‌​​‌​‌‌‌‌‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌​‌‌​‌‌​‌‌‌‌‌​‌‌‌​​‌​‌‌​‌​‌‌‌‌‌‌‌‌​‌​‌​‌‌​‌‌‌‌‌‌‌​​‌​‌‌​‌​‌‌‌​‌‌‌​​‌​‌​​‌‌‌‌‌​‌‌‌​​‌​‌​​‌‌‌‌‌‌‌‌‌‌‌‌​‌‌‌‌​‌‌‌‌‌‌‌‌‌‌​‌​‌‌​‌‌‌‌‌‌‌‌‌‌​‌‌​‌​‌‌‌​‌‌‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌‌‌‌​‌​‌‌‌‌‌‌‌‌‌‌​‌‌​‌​​‌​‌‌‌​‌‌‌​​‌​‌‌​‌​‌‌‌‌‌‌‌​‌‌​‌‌‌‌‌‌‌‌‌‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌​​‌​‌​​‌‌‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌​​‌​‌​​‌‌‌‌​‌​‌‌​​​‌‌‌‌‌‌‌‌‌​‌‌‌​‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌‌‌​‌‌​‌​‌‌​‌‌‌‌‌‌‌​‌‌​‌‌‌‌‌‌‌‌‌‌‌‌​​‌​‌​​‌​‌‌‌‌‌‌‌​‌‌​‌​‌‌‌‌‌‌‌‌‌‌‌‌‌​‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌‌​‌​‌​​‌‌‌‌‌​‌‌‌​‌‌​‌‌‌‌​‌‌‌‌‌‌‌​​‌​‌​​‌‌‌‌‌‌‌‌‌​‌‌​‌​​‌​‌‌‌​‌‌‌​​‌​‌​​‌‌‌‌‌‌‌‌‌​‌‌​‌​‌‌‌‌‌‌​‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌‌‌​‌‌​‌​‌‌​‌‌‌‌‌‌‌‌‌‌​‌​​‌​‌‌‌‌‌‌‌​‌‌​‌​‌‌‌‌‌‌‌‌‌‌‌‌‌​‌‌‌‌​‌‌‌‌‌‌‌​‌‌​‌‌​‌‌‌‌‌‌‌‌‌​‌‌​‌​​‌‌‌‌‌‌‌‌‌‌‌‌​‌​​‌​‌‌‌​‌‌‌‌​‌​‌​​‌‌‌‌‌​‌‌‌​‌‌​‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌‌​‌‌‌‌‌‌‌‌‌​‌‌​‌‌‌‌​‌‌‌‌‌‌‌​​‌​‌​​‌​‌‌‌‌‌‌‌​‌‌​‌​‌‌‌‌‌‌‌‌‌‌​​‌​‌‌​‌​‌‌‌‌‌‌‌​​‌​‌‌‌‌‌‌‌‌​‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌‌‌‌​‌​‌‌​‌​‌‌‌‌‌‌‌​​‌​‌​‌‌​‌‌‌‌‌‌‌‌‌‌​‌​​‌​‌‌‌‌‌‌‌‌‌‌​‌​​‌​‌‌‌‌‌‌‌‌‌‌​‌​‌‌​‌‌‌‌‌‌‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌‌​‌​‌‌‌‌​‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌​‌‌​‌‌‌‌​‌‌‌‌‌‌‌​​‌​‌​​‌​‌‌‌‌‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌​‌‌​‌‌​‌‌‌‌‌​‌‌‌​​‌​‌‌​‌​‌‌‌‌‌‌‌‌​‌​‌​‌‌​‌‌‌‌‌‌‌​​‌​‌‌​‌​‌‌‌​‌‌‌​​‌​‌​​‌‌‌‌‌​‌‌‌​​‌​‌​​‌‌‌‌‌‌‌‌‌‌‌‌​‌‌‌‌​‌‌‌‌‌‌‌‌‌‌​‌​‌‌​‌‌‌‌‌‌‌‌‌‌​‌‌​‌​‌‌‌​‌‌‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌‌‌‌​‌​‌‌‌‌‌‌‌‌‌‌​‌‌​‌​​‌​‌‌‌​‌‌‌​​‌​‌‌​‌​‌‌‌‌‌‌‌​‌‌​‌‌‌‌‌‌‌‌‌‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌​​‌​‌​​‌‌‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌​​‌​‌​​‌‌‌‌​‌​‌‌​​​‌‌‌‌‌‌‌‌‌​‌‌‌​‌‌‌‌​‌​‌​​‌​‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌​‌‌​‌​‌‌‌‌‌‌​‌‌‌‌​‌​‌‌​‌​‌‌‌​‌‌‌‌​‌​‌​​‌​‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌‌‌‌​‌​‌‌​‌‌‌​‌‌‌‌​‌​‌‌​‌​‌‌‌​‌‌‌‌​‌​‌​​‌​‌‌‌‌‌‌‌‌‌‌​‌​‌‌​‌‌‌​‌‌‌​‌‌​‌​‌‌​‌‌‌‌‌‌‌​‌‌​‌‌‌‌‌‌‌‌‌‌‌‌​​‌​‌​​‌​‌‌‌‌‌‌‌​‌‌​‌​‌‌‌‌‌‌‌‌‌‌‌‌‌​‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌‌​‌​‌​​‌‌‌‌‌​‌‌‌​‌‌​‌‌‌‌​‌‌‌‌‌‌‌​​‌​‌​​‌‌‌‌‌‌‌‌‌​‌‌​‌​​‌​‌‌‌​‌‌‌​​‌​‌​​‌‌‌‌‌‌‌‌‌‌‌‌​‌​‌‌​‌‌‌​‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌‌‌‌​‌​‌‌​‌​‌‌​‌‌​​‌​‌​‌‌​‌​‌​‌​​‌‌​‌​​‌​​​‌​​​​​​​‌​​‌​‌‌​​​‌‌​‌‌‌‌​‌​‌​​‌​‌‌‌‌‌‌‌​‌‌​‌​‌‌‌‌‌‌​‌‌‌​‌‌​‌​‌‌​‌‌‌‌‌‌‌​​‌​‌​‌‌​‌‌‌‌‌‌‌‌‌‌​‌‌‌‌​‌‌‌‌‌‌‌​‌‌​‌​​‌‌‌‌‌‌‌‌‌​‌‌​‌‌​‌​‌‌‌​‌‌‌‌​‌​‌​​‌‌‌‌‌​‌‌‌​‌‌​‌‌‌‌​‌‌‌‌‌‌‌​​‌​‌​‌‌​‌‌‌‌‌‌‌‌‌‌​‌​​‌​‌‌‌‌‌‌‌‌‌‌​‌​​‌​‌‌‌‌‌‌‌‌‌‌​‌​‌‌​‌‌‌‌‌‌‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌‌​‌​‌‌‌‌​‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌​‌‌​‌‌‌‌​‌‌‌‌‌‌‌​​‌​‌​​‌​‌‌‌‌‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌​‌‌​‌‌​‌‌‌‌‌​‌‌‌​​‌​‌‌​‌​‌‌‌‌‌‌‌‌​‌​‌​‌‌​‌‌‌‌‌‌‌​​‌​‌‌​‌​‌‌‌​‌‌‌​​‌​‌​​‌‌‌‌‌​‌‌‌​​‌​‌​​‌‌‌‌‌‌‌‌‌‌‌‌​‌‌‌‌​‌‌‌‌‌‌‌‌‌‌​‌​‌‌​‌‌‌‌‌‌‌‌‌‌​‌‌​‌​‌‌‌​‌‌‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌‌‌‌​‌​‌‌‌‌‌‌‌‌‌‌​‌‌​‌​​‌​‌‌‌​‌‌‌​​‌​‌‌​‌​‌‌‌‌‌‌‌​‌‌​‌‌‌‌‌‌‌‌‌‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌​​‌​‌​​‌‌‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌​​‌​‌​​‌‌‌‌​‌​‌‌​​​‌‌‌‌‌‌‌‌‌​‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌​‌‌​‌‌‌‌​‌‌‌‌‌‌‌​​‌​‌​​‌​‌‌‌‌‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌​‌‌​‌‌​‌‌‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌​‌‌‌‌​‌​‌​‌‌​‌‌‌​‌‌‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌‌‌​‌‌​‌​‌‌​‌‌‌‌‌‌‌​‌‌​‌‌‌‌‌‌‌‌‌‌‌‌​​‌​‌​​‌​‌‌‌‌‌‌‌​‌‌​‌​‌‌‌‌‌‌‌‌‌‌‌‌‌​‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌‌​‌​‌​​‌‌‌‌‌​‌‌‌​‌‌​‌‌‌‌​‌‌‌‌‌‌‌​​‌​‌​​‌‌‌‌‌‌‌‌‌​‌‌​‌​​‌​‌‌‌​‌‌‌​​‌​‌​​‌‌‌‌‌‌‌‌‌​‌‌​‌​‌‌‌‌‌‌​‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌‌‌​‌‌​‌​‌‌​‌‌‌‌‌‌‌‌‌‌​‌​​‌​‌‌‌‌‌‌‌​‌‌​‌​‌‌‌‌‌‌‌‌‌‌‌‌‌​‌‌‌‌​‌‌‌‌‌‌‌​‌‌​‌‌​‌‌‌‌‌‌‌‌‌​‌‌​‌​​‌‌‌‌‌‌‌‌‌‌‌‌​‌​​‌​‌‌‌​‌‌‌‌​‌​‌​​‌‌‌‌‌​‌‌‌​‌‌​‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌‌​‌‌‌‌‌‌‌‌‌​‌‌​‌‌‌‌​‌‌‌‌‌‌‌​​‌​‌​​‌​‌‌‌‌‌‌‌​‌‌​‌​‌‌‌‌‌‌‌‌‌‌​​‌​‌‌​‌​‌‌‌‌‌‌‌​​‌​‌‌‌‌‌‌‌‌​‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌‌‌‌​‌​‌‌​‌​‌‌‌‌‌‌‌​​‌​‌​‌‌​‌‌‌‌‌‌‌‌‌‌​‌​​‌​‌‌‌‌‌‌‌‌‌‌​‌​​‌​‌‌‌‌‌‌‌‌‌‌​‌​‌‌​‌‌‌‌‌‌‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌‌​‌​‌‌‌‌​‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌​‌‌​‌‌‌‌​‌‌‌‌‌‌‌​​‌​‌​​‌​‌‌‌‌‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌​‌‌​‌‌​‌‌‌‌‌​‌‌‌​​‌​‌‌​‌​‌‌‌‌‌‌‌‌​‌​‌​‌‌​‌‌‌‌‌‌‌​​‌​‌‌​‌​‌‌‌​‌‌‌​​‌​‌​​‌‌‌‌‌​‌‌‌​​‌​‌​​‌‌‌‌‌‌‌‌‌‌‌‌​‌‌‌‌​‌‌‌‌‌‌‌‌‌‌​‌​‌‌​‌‌‌‌‌‌‌‌‌‌​‌‌​‌​‌‌‌​‌‌‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌‌‌‌​‌​‌‌‌‌‌‌‌‌‌‌​‌‌​‌​​‌​‌‌‌​‌‌‌​​‌​‌‌​‌​‌‌‌‌‌‌‌​‌‌​‌‌‌‌‌‌‌‌‌‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌​​‌​‌​​‌‌‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌​​‌​‌​​‌‌‌‌​‌​‌‌​​​‌‌‌‌‌‌‌‌‌​‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌​‌‌​‌‌‌‌​‌‌‌‌‌‌‌​​‌​‌​​‌​‌‌‌‌‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌​‌‌​‌‌​‌‌‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌​‌‌‌‌​‌​‌​‌‌​‌‌‌​‌‌‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌‌​‌​‌​​‌​‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌​‌‌​‌​‌‌‌‌‌‌​‌‌‌‌​‌​‌‌​‌​‌‌‌​‌‌‌‌​‌​‌​​‌​‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌‌‌‌​‌​‌‌​‌‌‌​‌‌‌‌​‌​‌‌​‌​‌‌‌​‌‌‌‌​‌​‌​​‌​‌‌‌‌‌‌‌‌‌‌​‌​‌‌​‌‌‌​‌‌‌​‌‌​‌​‌‌​‌‌‌‌‌‌‌​‌‌​‌‌‌‌‌‌‌‌‌‌‌‌​​‌​‌​​‌​‌‌‌‌‌‌‌​‌‌​‌​‌‌‌‌‌‌‌‌‌‌‌‌‌​‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌​‌‌‌‌‌‌‌‌​‌‌‌‌​‌​‌​​‌‌‌‌‌​‌‌‌​‌‌​‌‌‌‌​‌‌‌‌‌‌‌​​‌​‌​​‌‌‌‌‌‌‌‌‌​‌‌​‌​​‌​‌‌‌​‌‌‌​​‌​‌​​‌‌‌‌‌‌‌‌‌‌‌‌​‌​‌‌​‌‌‌​‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌‌‌‌​‌​‌‌​‌​‌‌‌‌​​​​​‌​​​​​​‌‌‌‌​​​‌​‌​​​​​‌‌‌‌‌‌‌​​​​​​​‌‌​​​‌​‌‌‌​​​‌‌‌​​‌​‌‌‌​‌​‌​‌‌​​​​‌​​​‌‌‌​‌​​‌‌​‌​‌​‌‌​‌‌​​‌​‌‌‌​​‌​​​‌​‌‌​‌​​​​‌‌​​​​‌‌‌‌‌​‌​‌‌‌​​​​​​‌‌‌​‌‌‌​​​​​​‌‌​‌‌‌​​‌​‌‌​‌​‌‌‌​‌‌‌​​‌​‌‌​‌​‌‌‌​‌‌‌​​‌​‌‌​‌​‌‌‌​‌‌‌‌​‌​‌​​‌​‌‌‌​‌‌‌​​‌​‌‌​‌‌‌‌‌‌‌‌‌‌‌‌​‌​‌‌​‌‌‌​‌‌‌‌​‌​‌‌​‌​‌‌
No data