typescript 类型“[boolean,Dispatch〈SetStateAction>]”上不存在属性“current”< boolean>,ts(2339)

mutmk8jj  于 2023-03-04  发布在  TypeScript
关注(0)|答案(2)|浏览(345)

我正在向一个React/Typescript项目添加光标动画,在研究中遇到了一个工作得非常好的Codepen(X1 E0 F1 X)。
但是,当转换为Typescript文件时,我在cursorVisible.current上遇到错误Property 'current' does not exist on type '[boolean, Dispatch<SetStateAction<boolean>>]'.ts(2339)

const onMouseEnter = () => {
  cursorVisible.current = true;
  toggleCursorVisibility();
};

属性cursorVisible来自const cursorVisible = useState(false);
Typescript需要我做什么才能让current在Typescript中工作?阅读React Hooks文档时,我在useState上看不到对current的引用,有趣的是,它作为js文件工作,只是不在ts中。
在过去,我使用currentref,但从来没有跨越useState挂钩。
完整文件为

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

import MobileDetect from './MobileDetect';

interface CursorProps {
    color: string;
    outlineAlpha: number;
    dotSize: number;
    outlineSize: number;
    outlineScale: number;
    dotScale: number;
}

function AnimatedCursor({
    color = '220, 90, 90',
    outlineAlpha = 0.3,
    dotSize = 8,
    outlineSize = 8,
    outlineScale = 5,
    dotScale = 0.7,
}: CursorProps) {
    // Bail if Mobile
    if (typeof navigator !== 'undefined' && MobileDetect!.anyMobile())
        return <></>;

    const cursorOutline = useRef();
    const cursorDot = useRef();
    const requestRef = useRef();
    const previousTimeRef = useRef();
    const [width, setWidth] = useState(window.innerWidth);
    const [height, setHeight] = useState(window.innerHeight);
    const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
    const cursorVisible = useState(false);
    const cursorEnlarged = useState(false);

    const styles = {
        cursors: {
            zIndex: 999,
            pointerEvents: 'none',
            position: 'absolute',
            top: '50%',
            left: '50%',
            borderRadius: '50%',
            opacity: 0,
            transform: 'translate(-50%, -50%)',
            transition: 'opacity 0.15s ease-in-out, transform 0.15s ease-in-out',
        },
        cursorDot: {
            width: dotSize,
            height: dotSize,
            backgroundColor: `rgba(${color}, 1)`,
        },
        cursorOutline: {
            width: outlineSize,
            height: outlineSize,
            backgroundColor: `rgba(${color}, ${outlineAlpha})`,
        },
    };

    // Hide default cursor
    document.body.style.cursor = 'none';

    // Mouse Events
    const onMouseMove = (event: { pageX: number; pageY: number }) => {
        const { pageX: x, pageY: y } = event;
        setMousePosition({ x, y });
        positionDot(event);
    };
    const onMouseEnter = () => {
        cursorVisible.current = true;
        toggleCursorVisibility();
    };
    const onMouseLeave = () => {
        cursorVisible.current = false;
        toggleCursorVisibility();
    };
    const onMouseDown = () => {
        cursorEnlarged.current = true;
        toggleCursorSize();
    };
    const onMouseUp = () => {
        cursorEnlarged.current = false;
        toggleCursorSize();
    };

    // Set window hxw
    const onResize = () => {
        setWidth(window.innerWidth);
        setHeight(window.innerHeight);
    };

    /**
     * Hooks
     */
    useEffect(() => {
        // Bail if mobile
        document.addEventListener('mousemove', onMouseMove);
        document.addEventListener('mouseenter', onMouseEnter);
        document.addEventListener('mouseleave', onMouseLeave);
        document.addEventListener('mousedown', onMouseDown);
        document.addEventListener('mouseup', onMouseUp);
        window.addEventListener('resize', onResize);
        requestRef.current = requestAnimationFrame(animateDotOutline);
        handleLinkEvents();

        return () => {
            document.removeEventListener('mousemove', onMouseMove);
            document.removeEventListener('mouseenter', onMouseEnter);
            document.removeEventListener('mouseleave', onMouseLeave);
            document.removeEventListener('mousedown', onMouseDown);
            document.removeEventListener('mouseup', onMouseUp);
            window.removeEventListener('resize', onResize);
            cancelAnimationFrame(requestRef.current);
        };
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

    let { x, y } = mousePosition;
    const winDimensions = { width, height };
    let endX = winDimensions.width / 2;
    let endY = winDimensions.height / 2;

    /**
     * Toggle Cursor Visiblity
     */
    function toggleCursorVisibility() {
        if (cursorVisible.current) {
            cursorDot.current.style.opacity = 1;
            cursorOutline.current.style.opacity = 1;
        } else {
            cursorDot.current.style.opacity = 0;
            cursorOutline.current.style.opacity = 0;
        }
    }

    /**
     * Position Dot (cursor)
     * @param {event}
     */
    function positionDot(e: { pageX: number; pageY: number }) {
        cursorVisible.current = true;
        toggleCursorVisibility();
        // Position the dot
        endX = e.pageX;
        endY = e.pageY;
        cursorDot.current.style.top = `${endY}px`;
        cursorDot.current.style.left = `${endX}px`;
    }

    /**
     * Toggle Cursors Size/Scale
     */
    function toggleCursorSize() {
        if (cursorEnlarged.current) {
            cursorDot.current.style.transform = `translate(-50%, -50%) scale(${dotScale})`;
            cursorOutline.current.style.transform = `translate(-50%, -50%) scale(${outlineScale})`;
        } else {
            cursorDot.current.style.transform = 'translate(-50%, -50%) scale(1)';
            cursorOutline.current.style.transform = 'translate(-50%, -50%) scale(1)';
        }
    }

    /**
     * Handle Links Events
     * Applies mouseover/out hooks on all links
     * to trigger cursor animation
     */
    function handleLinkEvents() {
        document.querySelectorAll('a').forEach((el) => {
            el.addEventListener('mouseover', () => {
                cursorEnlarged.current = true;
                toggleCursorSize();
            });
            el.addEventListener('mouseout', () => {
                cursorEnlarged.current = false;
                toggleCursorSize();
            });
        });
    }

    /**
     * Animate Dot Outline
     * Aniamtes cursor outline with trailing effect.
     * @param {number} time
     */
    const animateDotOutline = (time: undefined) => {
        if (previousTimeRef.current !== undefined) {
            x += (endX - x) / 8;
            y += (endY - y) / 8;
            cursorOutline.current.style.top = `${y}px`;
            cursorOutline.current.style.left = `${x}px`;
        }
        previousTimeRef.current = time;
        requestRef.current = requestAnimationFrame(animateDotOutline);
    };

    return (
        <>
            <div
                ref={cursorOutline}
                id="cursor-outline"
                style={{ ...styles.cursors, ...styles.cursorOutline }}
            />
            <div
                ref={cursorDot}
                id="cursor-inner"
                style={{ ...styles.cursors, ...styles.cursorDot }}
            />
        </>
    );
}

export default AnimatedCursor;
hrirmatl

hrirmatl1#

在此张贴以防其他人遇到此问题:
我的问题是,我在重构时使用了大括号而不是方括号。大脑放屁时刻,但基本上我试图使用对象重构符号而不是从useState重构数组。

const { someState, setSomeState } = useState(false);

应该是

const [ someState, setSomeState ] = useState(false);
yyyllmsg

yyyllmsg2#

你必须询问你所使用的代码的作者。useState返回一个包含当前值的数组和一个setter函数来改变值。通常你会这样使用它:

let [cursorVisible, setCursorVisible] = useState(false);

// instead of cursorVisible.current = true
setCursorVisible(true);

数组上没有“当前”属性,除非它是由其他代码设置的,我认为这是不好的形式。

相关问题