在现代 React 中起作用的 React 长按,而不是 return "Rendered more hooks than during the previous render."?

React long press that works in modern react and don't return "Rendered more hooks than during the previous render."?

有一个解决方案 ...实际上有几个 - 但其中 none 适用于 React 17.0.2。它们都导致

Error: Rendered more hooks than during the previous render.

即使在评论中列出了修复(例如,使用 useref() 而不是 useState)。

所以我的问题是 - 我怎样才能在 React 17.0.2 和更新版本中拥有 long click/press/tap?

我修复它的尝试:

//
import {useCallback, useRef, useState} from "react";

const useLongPress = (
    onLongPress,
    onClick,
    {shouldPreventDefault = true, delay = 300} = {}
) => {
    //const [longPressTriggered, setLongPressTriggered] = useState(false);
    const longPressTriggered = useRef(false);
    const timeout = useRef();
    const target = useRef();
    
    const start = useCallback(
        event => {
            if (shouldPreventDefault && event.target) {
                event.target.addEventListener("touchend", preventDefault, {
                    passive: false
                });
                target.current = event.target;
            }
            timeout.current = setTimeout(() => {
                onLongPress(event);
                //setLongPressTriggered(true);
                longPressTriggered.current = true;
            }, delay);
        },
        [onLongPress, delay, shouldPreventDefault]
    );
    
    const clear = useCallback(
        (event, shouldTriggerClick = true) => {
            timeout.current && clearTimeout(timeout.current);
            shouldTriggerClick && !longPressTriggered && onClick(event);
            //setLongPressTriggered(false);
            longPressTriggered.current = false;
            if (shouldPreventDefault && target.current) {
                target.current.removeEventListener("touchend", preventDefault);
            }
        },
        [shouldPreventDefault, onClick, longPressTriggered]
    );
    
    return {
        onMouseDown: e => start(e),
        onTouchStart: e => start(e),
        onMouseUp: e => clear(e),
        onMouseLeave: e => clear(e, false),
        onTouchEnd: e => clear(e)
    };
};

const isTouchEvent = event => {
    return "touches" in event;
};

const preventDefault = event => {
    if (!isTouchEvent(event)) return;
    
    if (event.touches.length < 2 && event.preventDefault) {
        event.preventDefault();
    }
};

export default useLongPress;

RandomItem.js:

import React, {useEffect, useState} from 'react';
import Item from "../components/Item";
import Loader from "../../shared/components/UI/Loader";
import {useAxiosGet} from "../../shared/hooks/HttpRequest";
import useLongPress from '../../shared/hooks/useLongPress';


function RandomItem() {
    let content = null;
    let item = useAxiosGet('collection');
    
    if (item.error === true) {
        content = <p>There was an error retrieving a random item.</p>
    }
    
    if (item.loading === true) {
        content = <Loader/>
    }
    
    if (item.data) {
        const onLongPress = useLongPress();
        return (
            content =
                <div>
                    <h1 className="text-6xl font-normal leading-normal mt-0 mb-2">{item.data.name}</h1>
                    <Item name={item.data.name} image={item.data.filename} description={item.data.description}/>
                </div>
        )
    }
    
    return (
        <div>
            {content}
        </div>
    );
}

export default RandomItem;

(未经编辑的)useLongPress 函数应类似于以下示例使用:

import React, { useState } from "react";
import "./styles.css";
import useLongPress from "./useLongPress";

export default function App() {
  const [longPressCount, setlongPressCount] = useState(0)
  const [clickCount, setClickCount] = useState(0)

  const onLongPress = () => {
    console.log('longpress is triggered');
    setlongPressCount(longPressCount + 1)
  };

  const onClick = () => {
    console.log('click is triggered')
    setClickCount(clickCount + 1)
  }

  const defaultOptions = {
    shouldPreventDefault: true,
    delay: 500,
  };
  const longPressEvent = useLongPress(onLongPress, onClick, defaultOptions);

  return (
    <div className="App">
      <button {...longPressEvent}>use  Loooong  Press</button>
      <span>Long press count: {longPressCount}</span>
      <span>Click count: {clickCount}</span>
    </div>
  );
}

务必传入 onLongPress 函数、onClick 函数和选项对象。

这是一个带有 React 17.0.2 的 codesandbox,其中包含 useLongPress 的工作示例:https://codesandbox.io/s/uselongpress-forked-zmtem?file=/src/App.js