首页 > 解决方案 > 在现代反应中起作用的反应长按并且不返回“渲染的钩子比以前的渲染更多。”?

问题描述

这里有一个解决方案......实际上有几个 - 但它们都不适用于 React 17.0.2。他们都导致

错误:渲染的钩子比上一次渲染时更多。

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

所以我的问题是 - 我怎样才能在 React 17.0.2 和更新版本中长按/按下/点击?

我尝试修复它:

//https://stackoverflow.com/questions/48048957/react-long-press-event
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;

标签: javascriptreactjsdom-events

解决方案


(未编辑的)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 的代码框,其中有一个工作示例useLongPresshttps ://codesandbox.io/s/uselongpress-forked-zmtem?file=/src/App.js


推荐阅读