React throws an error "Can't assign to property" scrollLeft "on 1: not an object" When trying use ref in custom function

Viewed 254

I have a working animation of an object made with the "useRef" hook. Part of the code in this animation will be repeated several times, so I moved it into a separate function, but when I try to call this function, when rendering the component, I get the error "Can't assign to property" scrollLeft "on 1: not an object" what could be the problem?

Full code on codesandbox https://codesandbox.io/s/peaceful-silence-bm6hx?file=/src/scroll.js

enter image description here

import React, {useState, useEffect, useRef} from 'react'

const Scrollable = props => {

    const items = props.items;

    let ref = useRef()

    const [state, setState] = useState({
        isScrolling:false,
        clientX:0, 
        scrollX:0  
    })
    
   const [touchStart, setTouchStart] = useState(0);

   let frameId;
    
    const onMouseDown = e =>{...}
    
    const onMouseUp = e =>{
        if(ref && ref.current && !ref.current.contains(e.target)) {
            return;
        }
        e.preventDefault()

        let touchShift = touchStart - state.clientX
        let rez;
        let shift;

        if(touchShift > 0) {
            shift = 300 - touchShift
            rez = state.scrollX + shift

            if(rez>2100){
                rez =1800
                cancelAnimationFrame(frameId)
            }

            let speed = shift / 20
            let cur = state.scrollX
            
            frameId = requestAnimationFrame(animate)
            animate(cur,speed,rez)
        }
    }


    const animate = (cur, speed,rez) => {
            frameId = requestAnimationFrame(animate)
            cur = cur + speed
            ref.current.scrollLeft = cur.toFixed(2)

            if (Math.round(cur) === rez) {
                cancelAnimationFrame(frameId)
                setState({
                    ...state,
                    scrollX:rez,
                    isScrolling:false,
                })
            }
        }


    useEffect(() =>{
        document.addEventListener('mousedown',onMouseDown)
        document.addEventListener('mouseup',onMouseUp)
        return () => {
            document.removeEventListener('mousedown',onMouseDown)
            document.removeEventListener('mouseup',onMouseUp)
        }
    })
    useEffect(() =>{
    ref.current = requestAnimationFrame(animate)
    return () => {
        cancelAnimationFrame(ref.current)
     },[]})

    return (
        <div className={classes.charPage}>
            <div
                ref={ref}
                onMouseDown={onMouseDown}
                onMouseUp={onMouseUp}>
            </div>
        </div>

    )
}


export default Scrollable;

1 Answers

This error means you're trying to set a property on a number. In your useEffect you're doing this:

ref.current = requestAnimationFrame(animate)

requestAnimationFrame returns, according to MDN:

A long integer value, the request id, that uniquely identifies the entry in the callback list. This is a non-zero value, but you may not make any other assumptions about its value.

But you're also using the same ref for your DOM element. After your useEffect runs it will have set your ref to the rAF id which is a number causing your error when you try to set the scrollLeft property on the ref.

What you can try next to solve this is to use 2 separate refs, one for the requestAnimationFrame and one for your DOM element.

Related