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
라이브 데모
통상적인 클릭 동작의 기동을 약간 늦추면 필요한 결과를 얻을 수 있습니다.이 동작은 더블 클릭 이벤트가 발생하면 취소됩니다.
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 사양에서 삭제될 때까지 리액트는 기능을 지원해야 한다고 생각합니다.onDoubleClick
onClick
유감스럽게도 그렇지 않은 것 같습니다.
내가 한 일은 이렇다.개선을 위한 어떠한 제안도 환영합니다.
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
'programing' 카테고리의 다른 글
DD/MM/YYY 날짜 형식(Moment.js) (0) | 2023.03.19 |
---|---|
반응 - 순수 상태 비저장 구성 요소를 내보내는 방법 (0) | 2023.03.19 |
이 파일 형식을 처리하려면 적절한 로더가 필요할 수 있습니다. 현재 이 파일을 처리하도록 구성된 로더는 없습니다." (0) | 2023.03.19 |
의 생성자 매개 변수 0에는 'java.lang' 유형의 빈이 필요합니다.String'을 찾을 수 없습니다. (0) | 2023.03.19 |
에 대한 JOBject를 디시리얼화하는 방법NET 객체 (0) | 2023.03.14 |