what's wrong with my useEventListener ? Because each time I click on checkboxes I get this error :
useEventListener.js:14 Uncaught TypeError: callbackRef.current is not a function
at HTMLDocument.internalCallback (useEventListener.js:14:1)
useEventListener.js
import { useEffect, useRef } from 'react'
export default function useEventListener(eventType, callback) {
const callbackRef = useRef(callback)
useEffect(() => {
callbackRef.current = callback
})
useEffect(() => {
function internalCallback(e) {
return callbackRef.current(e)
}
document.addEventListener(eventType, internalCallback);
return () => document.removeEventListener(eventType, internalCallback)
}, [eventType])
}
I use my hook here:
export default function useQuery(query) {
const [queryList, setQueryList] = useState(null)
const [isMatch, setIsMatch] = useState(false)
useEffect(() => {
const list = window.matchMedia(query)
setQueryList(list)
setIsMatch(list.matches)
}, [query])
useEventListener('change', ((e) => setIsMatch(e.matches), queryList))
return isMatch
}
It seems the issue is in what you are passing to the custom hook:
useEventListener('change', ((e) => setIsMatch(e.matches), queryList))
The code here is passing a Comma Operator expression.
Comma Operator
The comma operator (
,) evaluates each of its operands (from left to right) and returns the value of the last operand. This lets you create a compound expression in which multiple expressions are evaluated, with the compound expression's final value being the value of the rightmost of its member expressions. This is commonly used to provide multiple parameters to a for loop.
In other words, the expression is evaluated and the result of the final operand is returned, queryList in this case.
It's not clear what the intent was in includeing queryList, but you should remove the comma operator expression and pass just the callback function to the custom hook.
Example:
useEventListener('change', (e) => setIsMatch(e.matches));
This is happening because you pass ((e) => setIsMatch(e.matches), queryList) as a second argument to useEventListener. Here's what MDS says:
The comma operator (
,) evaluates each of its operands (from left to right) and returns the value of the last operand.
So your useEventListener('change', ((e) => setIsMatch(e.matches), queryList)) is equivalent to useEventListener('change', queryList). Since queryList is not a function, you get the callbackRef.current is not a function error.
UPD
I would also remove the callback ref in the useEventListener hook. It makes sense to remove an old listener and attach a new one when the callback changes. It works in the same way but is way easier to read:
export default function useEventListener(eventType, callback) {
useEffect(() => {
function internalCallback(e) {
return callback(e);
}
document.addEventListener(eventType, internalCallback);
return () => document.removeEventListener(eventType, internalCallback);
}, [eventType, callback]);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With