简体   繁体   中英

How to fire function when the variables are set in a useEffect?

i have a function calculateDistance which calculate when the child component is in the center of the parent component. I want to fire the function on the onScroll event. But the variables I need for it a set in a useEffect and cannot use outside that scope. Has anyone an idea how to fix this?

export function Portfolio() {
  const portfolioRef = React.useRef(null)
  React.useEffect(() => {
    portfolioRef.current.scrollTop = 100
  }, []
  )
  return (
    <div  className={cx(styles.component, styles.scrollWrapper)}>
      <div className={styles.topIcon} dangerouslySetInnerHTML={{ __html: arrow }} />
      <div ref={portfolioRef} onScroll={calculateDistance} className={styles.scroll}>
        <PortfolioItem
          {...{ portfolioRef }}
          title='Article about Kaliber Academie'
          text='I wrote an article about my experience at Kaliber'
          link='https://medium.com/kaliberinteractive/hoe-technologie-het-hart-van-een-luie-scholier-veranderde-3cd3795c6e33'
          linkTekst='See Article' />
        <PortfolioItem
          {...{ portfolioRef }}
          title='Article about Kaliber Academie'
          text='hola'
          link='#'
          linkTekst='#' />
        <PortfolioItem
          {...{ portfolioRef }}
          title='Article about Kaliber Academie'
          text='hola'
          link='#'
          linkTekst='#' />
        <PortfolioItem
          {...{ portfolioRef }}
          title='Article about Kaliber Academie'
          text='hola'
          link='#'
          linkTekst='#' />
      </div>
      <div className={styles.bottomIcon} dangerouslySetInnerHTML={{ __html: arrow }} />
    </div>
  )
}

export function PortfolioItem({ text, title, link, linkTekst, portfolioRef }) {
  const portfolioItemRef = React.useRef(null)
  React.useEffect(() => {
    const element = portfolioItemRef.current
    const parent = portfolioRef.current
  }, [portfolioRef])
  return (
    <div ref={portfolioItemRef} className={styles.componentItem}>
      <div className={styles.title}>{title}</div>
      <div className={styles.content}>
        <div className={styles.text}>{text}</div>
        <div className={styles.links}>
          <a className={styles.linkTekst} href={link}>{linkTekst} </a>
          <div className={styles.linkIcon} dangerouslySetInnerHTML={{ __html:arrow }} />
        </div>
      </div>
    </div>
  )
}

function calculateDistance(parent, element) {
  if (!parent || !element) return 0
  const parentRect = parent.getBoundingClientRect()
  const parentCenter = (parentRect.top + parentRect.bottom) / 2
  const elementRect = element.getBoundingClientRect()
  const elementCenter = (elementRect.top + elementRect.bottom) / 2
  const distance = Math.abs(parentCenter - elementCenter)
  return clamp(distance / (parentRect.height / 2), 0, 1)
}

It doesnt look as if your calculated distance is being stored anywhere. You probably want the calulateDistance function to update a state variable which you refer to in Portfolio's useEffect.

You can create new variables from your component props and use useState() . you can then update them and reference them in your jsx and changing them will trigger your useEffect() , as long as you have it bounded correctly. Using props directly will only trigger your unbounded useEffect on the initial load. Additionally the reference you made 'portfolioItemRef' is only set when rendered and using it as the bound for the useEffect will not update to the calculated distance as is. move the calculated distance function into the portfolio component.

For Example:

const [stateText, setStateText] = useState(text)
useEffect(()=>{console.log('do something')},[stateText]);

here is a helpful explanation: https://medium.com/better-programming/tips-for-using-reacts-useeffect-effectively-dfe6ae951421

Best thing you can do is listen for the scroll event inside the useEffect

remove the onScroll attached to element

....
<div ref={portfolioRef} className={styles.scroll}>
....

inside useEffect

React.useEffect(() => {
    const calculateDistance = (parent, element) => {
        if (!parent || !element) return 0

        const parentRect = parent.getBoundingClientRect()
        const parentCenter = (parentRect.top + parentRect.bottom) / 2
        const elementRect = element.getBoundingClientRect()
        const elementCenter = (elementRect.top + elementRect.bottom) / 2
        const distance = Math.abs(parentCenter - elementCenter)

        return clamp(distance / (parentRect.height / 2), 0, 1)
    }

    //attach event listener 
    portfolioRef.current.addEventListener("scroll", calculateDistance);

    return () => {
        // remove the event listener when component unmounts
        portfolioRef.current.removeEventListener("scroll", calculateDistance);
    }
}, [])

Demo

you have to decide how to get the parent and element inside the calculateDistance

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM