Свойство 'current' не существует для типа '[boolean, Dispatch ] '. ts (2339) - PullRequest
0 голосов
/ 27 мая 2020

Я добавляю анимацию курсора в проект React / Typescript и в процессе исследования наткнулся на CodePen ( Анимированный компонент React Cursor ), который отлично работает.

Однако при преобразовании Файл Typescript Я столкнулся с ошибкой Property 'current' does not exist on type '[boolean, Dispatch<SetStateAction<boolean>>]'.ts(2339) на cursorVisible.current в

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

Свойство cursorVisible от const cursorVisible = useState(false);

Что мне нужно для Typescript current работает в Машинописи? Читая документы React Hooks, я не видел ссылки на current на useState, и что интересно, это работает как файл js, только не в ts.

Раньше я использовал current с ref, но не поперек 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;

1 Ответ

1 голос
/ 27 мая 2020

Вам нужно будет спросить автора кода, который вы используете. useState возвращает массив с текущим значением и функцию установки для изменения значения. Обычно вы использовали бы его так:

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

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

В массиве нет свойства 'current', если только оно не установлено другим кодом, что, я думаю, было бы плохим тоном.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...