programing

OnClick은 작동하지만 React 구성 요소에서는 OnDoubleClick이 무시됨

mytipbox 2023. 3. 19. 17:45
반응형

OnClick은 작동하지만 React 구성 요소에서는 OnDoubleClick이 무시됨

React로 지뢰찾기 게임을 만들고 있는데 셀이 한 번 클릭하거나 두 번 클릭할 때 다른 동작을 하고 싶습니다.현시점에서는onDoubleClick함수는 기동하지 않습니다.경고:onClick에 나타냅니다.를 삭제하면,onClick핸들러,onDoubleClick왜 두 사건 모두 효과가 없을까?하나의 요소에서 두 가지 이벤트를 모두 가질 수 있습니까?

/** @jsx React.DOM */

var Mine = React.createClass({
  render: function(){
    return (
      <div className="mineBox" id={this.props.id} onDoubleClick={this.props.onDoubleClick} onClick={this.props.onClick}></div>
    )
  }
});

var MineRow = React.createClass({
  render: function(){
    var width = this.props.width,
        row = [];
    for (var i = 0; i < width; i++){
      row.push(<Mine id={String(this.props.row + i)} boxClass={this.props.boxClass} onDoubleClick={this.props.onDoubleClick} onClick={this.props.onClick}/>)
    }
    return (
      <div>{row}</div>
    )
  }
})

var MineSweeper = React.createClass({
  handleDoubleClick: function(){
    alert('Double Clicked');
  },
  handleClick: function(){
    alert('Single Clicked');
  },
  render: function(){
    var height = this.props.height,
        table = [];
    for (var i = 0; i < height; i++){
      table.push(<MineRow width={this.props.width} row={String.fromCharCode(97 + i)} onDoubleClick={this.handleDoubleClick} onClick={this.handleClick}/>)
    }
    return (
      <div>{table}</div>
    )
  }
})

var bombs = ['a0', 'b1', 'c2'];
React.renderComponent(<MineSweeper height={5} width={5} bombs={bombs}/>, document.getElementById('content'));

이것은 React의 제한이 아니라 DOM의 제한입니다.click그리고.dblclick이벤트입니다.Quicksmode의 클릭 설명서에서 제시된 바와 같이:

클릭 이벤트와 dblick 이벤트를 동일한 요소에 등록하지 마십시오.단일 클릭 이벤트와 dblick 이벤트를 발생시키는 클릭 이벤트를 구분할 수 없습니다.

보다 최신의 메뉴얼에 대해서는, 이벤트의 W3C 사양에 다음과 같이 기술되어 있습니다.

포인팅 디바이스의 프라이머리 버튼을 요소 위로 두 번 클릭하면 사용자 에이전트가 이 이벤트를 디스패치해야 합니다.

두 번의 클릭 이벤트 후에 반드시 두 번 클릭 이벤트가 발생합니다.

편집:

jQuery의 핸들러는 다음과 같이 권장됩니다.

같은 요소에 대해 클릭 이벤트와 dblick 이벤트 모두에 핸들러를 바인드하는 것은 권장되지 않습니다.트리거되는 이벤트의 시퀀스는 브라우저마다 다르며 일부는 dblick 전에 두 번의 클릭 이벤트를 수신하고 다른 일부는 한 번만 수신합니다.더블클릭 감도(더블클릭으로 검출되는 최대 클릭 간격)는 운영체제 및 브라우저에 따라 다를 수 있으며 사용자가 설정할 수 있는 경우가 많습니다.

사용하는 대신ondoubleclick를 사용하여 현재 클릭 수를 가져올 수 있습니다.짧은 시간 동안 같은 영역에서 마우스를 클릭한 횟수입니다.

const handleClick = (e) => {
  switch (e.detail) {
    case 1:
      console.log("click");
      break;
    case 2:
      console.log("double click");
      break;
    case 3:
      console.log("triple click");
      break;
  }
};

return <button onClick={handleClick}>Click me</button>;

위의 예에서는 버튼을 세 번 클릭하면 3개의 케이스가 모두 인쇄됩니다.

click 
double click 
triple click 

라이브 데모

25777826/onclick-works-but-on-double-click-is-ignored on-react-component 편집

통상적인 클릭 동작의 기동을 약간 늦추면 필요한 결과를 얻을 수 있습니다.이 동작은 더블 클릭 이벤트가 발생하면 취소됩니다.

  let timer = 0;
  let delay = 200;
  let prevent = false;

  doClickAction() {
    console.log(' click');
  }
  doDoubleClickAction() {
    console.log('Double Click')
  }
  handleClick() {
    let me = this;
    timer = setTimeout(function() {
      if (!prevent) {
        me.doClickAction();
      }
      prevent = false;
    }, delay);
  }
  handleDoubleClick(){
    clearTimeout(timer);
    prevent = true;
    this.doDoubleClickAction();
  }
 < button onClick={this.handleClick.bind(this)} 
    onDoubleClick = {this.handleDoubleClick.bind(this)} > click me </button>

커스텀 훅을 사용하여 다음과 같이 간단한 클릭과 더블 클릭을 처리할 수 있습니다.

import { useState, useEffect } from 'react';

function useSingleAndDoubleClick(actionSimpleClick, actionDoubleClick, delay = 250) {
    const [click, setClick] = useState(0);

    useEffect(() => {
        const timer = setTimeout(() => {
            // simple click
            if (click === 1) actionSimpleClick();
            setClick(0);
        }, delay);

        // the duration between this click and the previous one
        // is less than the value of delay = double-click
        if (click === 2) actionDoubleClick();

        return () => clearTimeout(timer);
        
    }, [click]);

    return () => setClick(prev => prev + 1);
}

다음으로 컴포넌트에서 다음을 사용할 수 있습니다.

const click = useSingleAndDoubleClick(callbackClick, callbackDoubleClick);
<button onClick={click}>clic</button>

편집:

이것은 React 0.15.3에서는 문제가 되지 않습니다.


오리지널:

React 0.13.3의 경우 두 가지 해결 방법이 있습니다.

1. 콜백 참조

더블클릭의 경우에도 싱글클릭 핸들러는 2회(클릭마다 1회) 호출됩니다.

const ListItem = React.createClass({

  handleClick() {
    console.log('single click');
  },

  handleDoubleClick() {
    console.log('double click');
  },

  refCallback(item) {
    if (item) {
      item.getDOMNode().ondblclick = this.handleDoubleClick;
    }
  },

  render() {
    return (
      <div onClick={this.handleClick}
           ref={this.refCallback}>
      </div>
    );
  }
});

module.exports = ListItem;

2. lodash 데바운스

해결 .lodash하지만 복잡성 때문에 포기했어요.이 방법의 장점은 "클릭"이 한 번만 호출되고 "더블 클릭"의 경우 전혀 호출되지 않는다는 것입니다.

import _ from 'lodash'

const ListItem = React.createClass({

  handleClick(e) {
    if (!this._delayedClick) {
      this._delayedClick = _.debounce(this.doClick, 500);
    }
    if (this.clickedOnce) {
      this._delayedClick.cancel();
      this.clickedOnce = false;
      console.log('double click');
    } else {
      this._delayedClick(e);
      this.clickedOnce = true;
    }
  },

  doClick(e) {
    this.clickedOnce = undefined;
    console.log('single click');
  },

  render() {
    return (
      <div onClick={this.handleClick}>
      </div>
    );
  }
});

module.exports = ListItem;

비밀리에

더블클릭은 쉽게 검출되는 것이 아니라 좋든 나쁘든 운영체제에 널리 보급되어 있기 때문에 사용자가 이해할 수 있는 패러다임입니다.게다가, 이것은 최신 브라우저가 여전히 지원하는 패러다임이다.DOM 사양에서 삭제될 때까지 리액트는 기능을 지원해야 한다고 생각합니다.onDoubleClickonClick유감스럽게도 그렇지 않은 것 같습니다.

내가 한 일은 이렇다.개선을 위한 어떠한 제안도 환영합니다.

class DoubleClick extends React.Component {
  state = {counter: 0}

  handleClick = () => {
   this.setState(state => ({
    counter: this.state.counter + 1,
  }))
 }


  handleDoubleClick = () => {
   this.setState(state => ({
    counter: this.state.counter - 2,
  }))
 }

 render() {
   return(
   <>
    <button onClick={this.handleClick} onDoubleClick={this.handleDoubleClick>
      {this.state.counter}
    </button>
   </>
  )
 }
}

타이프 스크립트 리액트 훅을 사용하여 @erminea-nea의 답변에서 영감을 얻어 클릭 1회 및 클릭 2회 모두를 캡처합니다.

import {useEffect, useState} from "react";

export function useSingleAndDoubleClick(
    handleSingleClick: () => void,
    handleDoubleClick: () => void,
    delay = 250
) {
  const [click, setClick] = useState(0);

  useEffect(() => {
    const timer = setTimeout(() => {
      if (click === 1) {
        handleSingleClick();
      }
      setClick(0);
    }, delay);

    if (click === 2) {
      handleDoubleClick();
    }

    return () => clearTimeout(timer);

  }, [click, handleSingleClick, handleDoubleClick, delay]);

  return () => setClick(prev => prev + 1);
}

사용방법:

<span onClick={useSingleAndDoubleClick(
  () => console.log('single click'),
  () => console.log('double click')
)}>click</span>

이것은 에르미나의 솔루션을 기반으로 한 증분값과 식별값을 가진 Like 버튼의 솔루션입니다.

useEffect(() => {
    let singleClickTimer;
    if (clicks === 1) {
      singleClickTimer = setTimeout(
        () => {
          handleClick();
          setClicks(0);
        }, 250);
    } else if (clicks === 2) {
      handleDoubleClick();
      setClicks(0);
    }
    return () => clearTimeout(singleClickTimer);
  }, [clicks]);

  const handleClick = () => {
    console.log('single click');
    total = totalClicks + 1;
    setTotalClicks(total);
  }

  const handleDoubleClick = () => {
    console.log('double click');
    if (total > 0) {
      total = totalClicks - 1;
    }
    setTotalClicks(total);
  }

  return (
    <div
      className="likeButton"
      onClick={() => setClicks(clicks + 1)}
    >
      Likes | {totalClicks}
    </div>
)

안 돼, 안 되다waitForDoubleClick를 반환하다Promise더블클릭이 실행되지 않은 경우에만 해결됩니다.그렇지 않으면 거부됩니다.시간은 조정할 수 있습니다.

    async waitForDoubleClick() {
    return new Promise((resolve, reject) => {
      const timeout = setTimeout(() => {
        if (!this.state.prevent) {
          resolve(true);
        } else {
          reject(false);
        }
      }, 250);
      this.setState({ ...this.state, timeout, prevent: false })
    });
  }
  clearWaitForDoubleClick() {
    clearTimeout(this.state.timeout);
    this.setState({
      prevent: true
    });
  }
  async onMouseUp() {
    try {
      const wait = await this.waitForDoubleClick();
      // Code for sinlge click goes here.
    } catch (error) {
      // Single click was prevented.
      console.log(error)
    }
  }

다음은 TypeScript의 React용 솔루션입니다.

import { debounce } from 'lodash';

const useManyClickHandlers = (...handlers: Array<(e: React.UIEvent<HTMLElement>) => void>) => {
  const callEventHandler = (e: React.UIEvent<HTMLElement>) => {
    if (e.detail <= 0) return;
    const handler = handlers[e.detail - 1];
    if (handler) {
      handler(e);
    }
  };

  const debounceHandler = debounce(function(e: React.UIEvent<HTMLElement>) {
    callEventHandler(e);
  }, 250);

  return (e: React.UIEvent<HTMLElement>) => {
    e.persist();
    debounceHandler(e);
  };
};

이 유틸리티의 사용 예를 다음에 나타냅니다.

const singleClickHandler = (e: React.UIEvent<HTMLElement>) => {
  console.log('single click');
};
const doubleClickHandler = (e: React.UIEvent<HTMLElement>) => {
  console.log('double click');
};
const clickHandler = useManyClickHandlers(singleClickHandler, doubleClickHandler);

// ...

<div onClick={clickHandler}>Click me!</div>

Erminea Nea 솔루션을 업데이트하여 전파를 멈출 수 있도록 했습니다.저 같은 경우에는 다이내믹한 소품을 1-2클릭 핸들러에 전달해야 했습니다.모든 공적은 에르미나 니아에게 있다.

여기 제가 생각해낸 훅이 있습니다.

import { useState, useEffect } from 'react';

const initialState = {
  click: 0,
  props: undefined
}

function useSingleAndDoubleClick(actionSimpleClick, actionDoubleClick, delay = 250) {
  const [state, setState] = useState(initialState);

  useEffect(() => {
    const timer = setTimeout(() => {
    // simple click
      if (state.click === 1) actionSimpleClick(state.props);
      setState(initialState);
    }, delay);

    // the duration between this click and the previous one
    // is less than the value of delay = double-click
    if (state.click === 2) actionDoubleClick(state.props);

    return () => clearTimeout(timer);
      
  }, [state.click]);

  return (e, props) => {
    e.stopPropagation()

    setState(prev => ({
      click: prev.click + 1,
      props
    }))
  }
}

export default useSingleAndDoubleClick

일부 컴포넌트에서의 사용:

const onClick = useSingleAndDoubleClick(callbackClick, callbackDoubleClick)

<button onClick={onClick}>Click me</button>

또는

<button onClick={e => onClick(e, someOtherProps)}>Click me</button>
import React, { useState } from "react";

const List = () => {

const [cv, uv] = useState("nice");

  const ty = () => {

    uv("bad");

  };

  return (

    <>

      <h1>{cv}</h1>

      <button onDoubleClick={ty}>Click to change</button>

    </>

  );

};

export default List;

언급URL : https://stackoverflow.com/questions/25777826/onclick-works-but-ondoubleclick-is-ignored-on-react-component

반응형