How to use useEffect() correctly?

Viewed 205

I want to change style by scrolling.

This code isn't working correctly . When I rolling up and down too many times and too fast, then the browser is going to freeze, crash.

I think I used useEffect() wrong. How can I solve this issue.

const ArticleItem = ({title, content, active, chapter, program, id, scrollPos}) => {
  const ref = useRef(null);
  const client = useApolloClient();

  useEffect(() => {
    if(ref.current.offsetTop <= (scrollPos + 200)) {
      client.writeData({data: {
        curChapter: chapter.num,
        curArticle: id,
        curProgram: program.name
      }});
    }
  });

  if(active === false)
    return ( // Inactive Article
      <div className='section-item' ref={ref}>
        <h2>{title.toUpperCase()}</h2>
        <ReactMarkdown source={content} />
        <br />
      </div>
    )
  return (  // Active Article
    <div className='section-item active' ref={ref}>
      <h2>{title.toUpperCase()}</h2>
      <ReactMarkdown source={content} />
      <br />
    </div>
  )
}

As a Result, I faced this warning.

Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.

I think this is the reason of issue?!

2 Answers

Based on my comment above, you need to include the dependency array for useEffect also. In the current way it is running infinitely. Probably you want to include scrollPos into that thus it would only triggered once scrollPos is changing.

Try the following:

useEffect(() => {
    if(ref.current.offsetTop <= (scrollPos + 200)) {
      client.writeData({data: {
        curChapter: chapter.num,
        curArticle: id,
        curProgram: program.name
      }});
    }
}, [scrollPos]);

I hope this helps!

Well, the problem is triggered all the time you can use the scroll event listener and make your changes when this event is triggered.

const [scrollItem, setScrollItem] = useState(null);

const handleScroll() {
  if(scrollItem) {
     // logic goes here
  }
}

useEffect(() => {
  window.addEventListener('scroll', handleScroll);

  return () => {
    window.removeEventListener('scroll', handleScroll);
  };
}, []); // initialize event only once

return (
   <div ref={setScrollItem}>
      ...
   </div>
);

EDIT

Avoid that solution, @norbitrial is right

Related