简体   繁体   English

在 useEffect 中设置变量时如何触发 function?

[英]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.我有一个 function calculateDistance计算子组件何时位于父组件的中心。 I want to fire the function on the onScroll event.我想在onScroll事件上触发 function。 But the variables I need for it a set in a useEffect and cannot use outside that scope.但是我需要的变量在useEffect中设置并且不能在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.您可能希望 calulateDistance function 更新您在投资组合的 useEffect 中引用的 state 变量。

You can create new variables from your component props and use useState() .您可以从组件道具创建新变量并使用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.然后,您可以更新它们并在您的 jsx 中引用它们并更改它们将触发您的useEffect() ,只要您的边界正确。 Using props directly will only trigger your unbounded useEffect on the initial load.直接使用道具只会在初始加载时触发您的无限 useEffect。 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.此外,您所做的“portfolioItemRef”引用仅在渲染时设置,并将其用作 useEffect 的界限不会按原样更新为计算的距离。 move the calculated distance function into the portfolio component.将计算出的距离 function 移动到投资组合组件中。

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这是一个有用的解释: 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您可以做的最好的事情是监听useEffect中的滚动事件

remove the onScroll attached to element移除附加到元素的onScroll

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

inside useEffect内部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您必须决定如何在calculateDistance中获取parent元素和element

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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