0

I want to add an eventListener to a node in my React component. I am selecting the node with a useRef hook. I am useCallback since the useRef is null on it's first render.

const offeringsContainer = useRef(null);

const setOfferingsContainer = useCallback((node) => {
  if (node !== null) {
    offeringsContainer.current = node;
  }
}, []);

My issue is that my useEffect is not reacting to any changes done to the offeringContainer ref. Meaning, offeringContainer.current is null.

useEffect(() => {
    checkHeaderState();
    offeringsContainer.current.addEventListener("wheel", onOfferingsContainerWheel, { passive: false });
}, [offeringsContainer.current]);

This is my JSX:

return (
    <Fragment>
      <div className="card-business-products-services-title-text">
        Products &amp; Services
      </div>
      <div
        className="card-business-products-services-container"
        id="card-business-products-services-container"
        onWheel={onOfferingsContainerWheel}
        ref={setOfferingsContainer}
      >
        {renderOfferings()}
      </div>
    </Fragment>
);

I know I am doing something incorrectly, but my useEffect hook should be listening to any changes from offeringsContainer.current.

Isaac Medina
  • 332
  • 1
  • 5
  • 17
  • 1
    You can simply assign the ref in the jsx: `ref={offeringsContainer}` and since `useEffect` runs after the first render accessing `offeringsContainer.current` will return the node. You'll also want to pass a cleanup call back to the return of your `useEffect` that removes the listener. But even better would be to use the [`onwheel`](https://reactjs.org/docs/events.html#wheel-events) synthetic event – pilchard Nov 27 '20 at 21:51
  • why are you assigning `onWheel` to the element and also manually adding a listener? – pilchard Nov 27 '20 at 22:08
  • @pilchard to remove the “passive: true” – Isaac Medina Nov 27 '20 at 22:08
  • Doing both assigns two listeners so choose one or the other. – pilchard Nov 27 '20 at 22:15

1 Answers1

2

You can just past offeringsContainer to the ref of the component. useEffect will be invoked only when there is first rendering that's why your offeringsContainer.current will not be null.

And you forgot to remove listener after the component will be unmounted.

Your code should be like this;

const offeringsContainer = useRef(null);

useEffect(() => {
  checkHeaderState();
  offeringsContainer.current.addEventListener(
    "wheel",
    onOfferingsContainerWheel,
    { passive: false }
  );

  return () => offeringsContainer.current.removeEventListener("wheel");
}, []);

return (
  <Fragment>
    <div className="card-business-products-services-title-text">
      Products &amp; Services
    </div>
    <div
      className="card-business-products-services-container"
      id="card-business-products-services-container"
      onWheel={onOfferingsContainerWheel}
      ref={offeringsContainer}
    >
      {renderOfferings()}
    </div>
  </Fragment>
);

Example: https://codesandbox.io/s/wizardly-banzai-3fhju?file=/src/App.js

QuazBuzz
  • 1,112
  • 1
  • 8
  • 18