Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

需求taro3小程序react hooks对createIntersectionObserver api的支持 #9237

Closed
FE-wuhao opened this issue Apr 29, 2021 · 10 comments
Closed
Labels
enhancement New feature or request resolved

Comments

@FE-wuhao
Copy link

这个特性解决了什么问题?

createIntersectionObserver(
/** 自定义组件实例 /
component: General.IAnyObject,
/
* 选项 */
options?: createIntersectionObserver.Option,
): IntersectionObserver

目前的createIntersectionObserver必传一个上下文参数component,但是hooks函数组件中拿不到this

这个 API 长什么样?

可以无需传入上下文,适配函数组件使用

@taro-bot2 taro-bot2 bot added the enhancement New feature or request label Apr 29, 2021
@luckyadam
Copy link
Member

传入的是,Taro. getCurrentInstance() 返回的 page

@codeLose
Copy link

哪个是page实例 不是组件实例 我试了不可以

@FE-wuhao
Copy link
Author

FE-wuhao commented Oct 20, 2021

哪个是page实例 不是组件实例 我试了不可以

时间隔得有点久了 当时按照官方的答复确实解决问题了,部分代码贴下面

  // 监听最顶部元素是否在视野内
  useSafeEffect(() => {
    const observer = Taro.createIntersectionObserver(
      Taro.getCurrentInstance().page as PageInstance,
      {
        observeAll: true,
      }
    )
    setTimeout(() => {
      observer.relativeTo('.list-observer').observe('.list-observer-top', (res) => {
        // 最顶部元素暴露在视口的比例大于0时则触顶
        if (res.intersectionRatio > 0) {
          setReachTop(true)
        } else {
          setReachTop(false)
        }
      })
    }, 0)

    return () => {
      if (observer) observer.disconnect()
    }
  }, [])

useSafeEffect是我自己基于useEffect封装的hook,你直接用useEffect就好了,as PageInstance是ts断言,如果你用的js就删掉吧

@ickg5
Copy link
Contributor

ickg5 commented Nov 5, 2021

哪个是page实例 不是组件实例 我试了不可以

时间隔得有点久了 当时按照官方的答复确实解决问题了,部分代码贴下面

  // 监听最顶部元素是否在视野内
  useSafeEffect(() => {
    const observer = Taro.createIntersectionObserver(
      Taro.getCurrentInstance().page as PageInstance,
      {
        observeAll: true,
      }
    )
    setTimeout(() => {
      observer.relativeTo('.list-observer').observe('.list-observer-top', (res) => {
        // 最顶部元素暴露在视口的比例大于0时则触顶
        if (res.intersectionRatio > 0) {
          setReachTop(true)
        } else {
          setReachTop(false)
        }
      })
    }, 0)

    return () => {
      if (observer) observer.disconnect()
    }
  }, [])

useSafeEffect是我自己基于useEffect封装的hook,你直接用useEffect就好了,as PageInstance是ts断言,如果你用的js就删掉吧

这个 useSafeEffect 是怎么实现的,大佬

@FE-wuhao
Copy link
Author

FE-wuhao commented Nov 5, 2021

哪个是page实例 不是组件实例 我试了不可以

时间隔得有点久了 当时按照官方的答复确实解决问题了,部分代码贴下面

  // 监听最顶部元素是否在视野内
  useSafeEffect(() => {
    const observer = Taro.createIntersectionObserver(
      Taro.getCurrentInstance().page as PageInstance,
      {
        observeAll: true,
      }
    )
    setTimeout(() => {
      observer.relativeTo('.list-observer').observe('.list-observer-top', (res) => {
        // 最顶部元素暴露在视口的比例大于0时则触顶
        if (res.intersectionRatio > 0) {
          setReachTop(true)
        } else {
          setReachTop(false)
        }
      })
    }, 0)

    return () => {
      if (observer) observer.disconnect()
    }
  }, [])

useSafeEffect是我自己基于useEffect封装的hook,你直接用useEffect就好了,as PageInstance是ts断言,如果你用的js就删掉吧

这个 useSafeEffect 是怎么实现的,大佬

这个是useSafeEffect的代码,自己写的,如有不对请指正

import { useEffect } from 'react'

function useSafeEffect<T>(
  cb: (cancel: boolean) => void | Promise<void> | Function | Promise<Function>,
  depth: T[]
) {
  useEffect(() => {
    let isNextRender = false

    const returnValue = cb(!isNextRender)

    return () => {
      // 递归判断返回值
      // 如果是promise一直往下递归
      // 如果是函数则执行函数
      // 否则无事发生
      const recursion = (result) => {
        if (result instanceof Promise) {
          result.then((subResult) => {
            recursion(subResult)
          })
        } else if (result instanceof Function) {
          result()
        } else {
          return
        }
      }

      recursion(returnValue)

      isNextRender = true
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, depth)
}

export default useSafeEffect

因为useEffect会存在内存泄露的问题,所以利用useEffect的return函数,在下一帧或者组件卸载的时候执行的特性,通过isNextRender这个标记来判断是否需要更新副作用,从而避免内存安全问题。上面那个用例没用发挥保证安全的作用,正确的用法如下:

  useSafeEffect((isCurrentRender) => {
    if (isCurrentRender) {
      setStateB(stateA)
    }
  }, [stateA])

@ickg5
Copy link
Contributor

ickg5 commented Nov 5, 2021

@FE-wuhao 学到了

@liyiming22
Copy link

@FE-wuhao

  // 监听最顶部元素是否在视野内
  useSafeEffect(() => {
    const observer = Taro.createIntersectionObserver(
      Taro.getCurrentInstance().page as PageInstance,
      {
        observeAll: true,
      }
    )
    setTimeout(() => {
      observer.relativeTo('.list-observer').observe('.list-observer-top', (res) => {
        // 最顶部元素暴露在视口的比例大于0时则触顶
        if (res.intersectionRatio > 0) {
          setReachTop(true)
        } else {
          setReachTop(false)
        }
      })
    }, 0)

    return () => {
      if (observer) observer.disconnect()
    }
  }, [])

这里创建完 observer 对象之后,后面的监听 observer.relativeTo 为什么要包在 setTimeout 里面以异步的形式调用呢?

@ShawnZeng
Copy link

这个方法有效,十分感谢!

@tennessine
Copy link

十分有用,言射言射!

@NoirVoider
Copy link

NoirVoider commented Mar 16, 2023

十分感谢 👍👍 有用 给楼主赞

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request resolved
Projects
None yet
Development

No branches or pull requests

9 participants