Reputation: 101
I'm trying to handle scroll event so a new class name can be added to an element upon scrolling.
What I have done:
Here's the code:
const onScrollHandler = (e: React.ChangeEvent):void => {
if (!e.target.classList.contains('onScrollBar')) {
e.target.classList.add('onScrollBar');
}
};
useEffect(() => {
window.addEventListener('scroll', onScrollHandler, true);
return () => {
window.removeEventListener('scroll', onScrollHandler, true);
};
}, []);
The issue I got:
onScrollHandler
shows this errorNo overload matches this call.
Overload 1 of 2, '(type: "scroll", listener: (this: Window, ev: Event) => any, options?: boolean | AddEventListenerOptions | undefined): void', gave the following error.
Argument of type '(e: React.ChangeEvent) => void' is not assignable to parameter of type '(this: Window, ev: Event) => any'.
Types of parameters 'e' and 'ev' are incompatible.
Type 'Event' is missing the following properties from type 'ChangeEvent<Element>': nativeEvent, isDefaultPrevented, isPropagationStopped, persist
Overload 2 of 2, '(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | undefined): void', gave the following error.
Argument of type '(e: React.ChangeEvent) => void' is not assignable to parameter of type 'EventListenerOrEventListenerObject'.
Type '(e: React.ChangeEvent) => void' is not assignable to type 'EventListener'.
Types of parameters 'e' and 'evt' are incompatible.
Type 'Event' is not assignable to type 'ChangeEvent<Element>'.ts(2769)
I think this is something to do with the e: React.ChangeEvent
. So what should be the correct event type in this case?
Many thanks!
Upvotes: 2
Views: 10207
Reputation: 350
First, you need to use document
to add the listener, or that scoll listener will not do anything.
It seems React.ChangeEvent
is only applicable for <select>
, <input>
or <textarea>
onChange events.
So you need to use the type Event
for scroll events and such. Now, the scroll target is most of the time the DOM, which does not have a classList
. To get the proper type, I used the as
keyword and checked if it has a classList
.
Here's my full code:
const onScrollHandler = (e: Event) => {
if (!e.target)
return
const target = e.target as Element
if (target.classList === undefined) // ensure it's not the DOM
return
if (!target.classList.contains('onScrollBar'))
target.classList.add('onScrollBar');
};
useEffect(() => {
document.addEventListener('scroll', onScrollHandler, true);
return () => {
document.removeEventListener('scroll', onScrollHandler, true);
};
}, []);
Upvotes: 3
Reputation: 101
My colleague has helped me with this solution and it works wonders for me :D
So basically, the event type should be changed as Event
and when calling e.target
, we need to specify it as Element
Here's the fix:
const onScrollHandler = (e: Event):void => {
if((e.target as Element).classList.contains('onScrollBar')) {
((e.target as Element).classList.add('onScrollBar'))
}
};
useEffect(() => {
document.addEventListener('scroll', onScrollHandler, true);
return () => {
document.removeEventListener('scroll', onScrollHandler, true);
};
}, []);
Upvotes: 1