首页 > 解决方案 > add condition with variable inside const IntersectionObserver

问题描述

I have following hook that is added on start:

const scrollObserver = useCallback(
    (node) => {
        new IntersectionObserver((entries) => {
            entries.forEach((en) => {
                if (en.intersectionRatio > 0.5) {
                    pagerDispatch({ type: 'ADVANCE_PAGE' }
                }
            })
        }).observe(node)
    },
    [pagerDispatch]
)

useEffect(
    () => {         
        if (bottomBoundaryRef.current) {
            scrollObserver(bottomBoundaryRef.current)
        }
    },
    [scrollObserver, bottomBoundaryRef]
)

The problem I'm facing that I want to add if condition with a variable value that updates over time. If I add following code then data.length is always 0. I guess that's because it has in store the state that was on start.

if (en.intersectionRatio > 0.5) {
    if (data.length <= iScrollMax) {
        pagerDispatch({ type: 'ADVANCE_PAGE' })
    }
}

How do I add condition with updatable variable here?

ps. I've tried making separate fuction but that did not work too. example

function upd() {        
    if (data.length <= iScrollMax) {
        pagerDispatch({ type: 'ADVANCE_PAGE' })
    }
}

const scrollObserver = useCallback(
    (node) => {
        new IntersectionObserver((entries) => {
            entries.forEach((en) => {
                if (en.intersectionRatio > 0.5) {
                    upd()
                }
            })
        }).observe(node)
    },
    [pagerDispatch]
)

标签: javascriptreactjsreact-hooks

解决方案


You aren't seeing the updated data value in the function because of closure. Your function is only recreated on change on pagerDispatch and so when the data values update, it isn't made aware of it and keeps using the old data value it had when it was created

The solution is to add data as dependency to useCallback and also ensure you cleanup your observer in useEffect

const scrollObserver = useCallback(
    (node) => {
        return new IntersectionObserver((entries) => {
            entries.forEach((en) => {
                if (en.intersectionRatio > 0.5) {
                  if (data.length <= iScrollMax) {
                    pagerDispatch({ type: 'ADVANCE_PAGE' }
                  }
                }
            })
        }).observe(node)
    },
    [pagerDispatch, data]
)

useEffect(
    () => { 
        let observer;        
        if (bottomBoundaryRef.current) {
            observer=scrollObserver(bottomBoundaryRef.current)
        }

       return () => {
           observer && observer.disconnect();
       }
    },
    [scrollObserver, bottomBoundaryRef]
)

Approach 2: There is a getaway to this via a ref

const dataRef = useRef(data);
useEffect(() => {
   dataRef.current = data;
}, [data]);
const scrollObserver = useCallback(
        (node) => {
            return new IntersectionObserver((entries) => {
                entries.forEach((en) => {
                    if (en.intersectionRatio > 0.5) {
                      if (dataRef.current.length <= iScrollMax) {
                        pagerDispatch({ type: 'ADVANCE_PAGE' }
                      }
                    }
                })
            }).observe(node)
        },
        [pagerDispatch]
    )

    useEffect(
        () => { 
            let observer;        
            if (bottomBoundaryRef.current) {
                observer=scrollObserver(bottomBoundaryRef.current)
            }

           return () => {
               observer && observer.disconnect();
           }
        },
        [scrollObserver, bottomBoundaryRef]
    )

推荐阅读