데바운스 어떻게 해요?
React.js에서 디바운스는 어떻게 수행하나요?
handleOnChange를 디바운스하고 싶습니다.
로 시도했다.debounce(this.handleOnChange, 200)
효과가 없어요.
function debounce(fn, delay) {
var timer = null;
return function() {
var context = this,
args = arguments;
clearTimeout(timer);
timer = setTimeout(function() {
fn.apply(context, args);
}, delay);
};
}
var SearchBox = React.createClass({
render: function() {
return <input type="search" name="p" onChange={this.handleOnChange} />;
},
handleOnChange: function(event) {
// make ajax call
}
});
2019년 : Try Hook + 약속 파기
이것이 제가 이 문제를 해결할 수 있는 가장 최신 버전입니다.다음을 사용합니다.
- 비동기 기능을 디바운스하기 위한 awesome-communce-module
- use-disclosed 기능을 컴포넌트에 저장합니다.
- 결과를 컴포넌트에 입력하기 위한 react-closc-hook
이것은 초기 배선이지만, 사용자가 직접 원시 블록을 구성하고 있으며, 사용자가 직접 사용자 지정 후크를 만들 수 있으므로 이 작업은 한 번만 수행하면 됩니다.
// Generic reusable hook
const useDebouncedSearch = (searchFunction) => {
// Handle the input text state
const [inputText, setInputText] = useState('');
// Debounce the original search async function
const debouncedSearchFunction = useConstant(() =>
AwesomeDebouncePromise(searchFunction, 300)
);
// The async callback is run each time the text changes,
// but as the search function is debounced, it does not
// fire a new request on each keystroke
const searchResults = useAsync(
async () => {
if (inputText.length === 0) {
return [];
} else {
return debouncedSearchFunction(inputText);
}
},
[debouncedSearchFunction, inputText]
);
// Return everything needed for the hook consumer
return {
inputText,
setInputText,
searchResults,
};
};
그런 다음 후크를 사용할 수 있습니다.
const useSearchStarwarsHero = () => useDebouncedSearch(text => searchStarwarsHeroAsync(text))
const SearchStarwarsHeroExample = () => {
const { inputText, setInputText, searchResults } = useSearchStarwarsHero();
return (
<div>
<input value={inputText} onChange={e => setInputText(e.target.value)} />
<div>
{searchResults.loading && <div>...</div>}
{searchResults.error && <div>Error: {search.error.message}</div>}
{searchResults.result && (
<div>
<div>Results: {search.result.length}</div>
<ul>
{searchResults.result.map(hero => (
<li key={hero.name}>{hero.name}</li>
))}
</ul>
</div>
)}
</div>
</div>
);
};
여기에서는 이 예를 실행하고 있습니다.자세한 내용은 react-async-hook 매뉴얼을 참조해 주십시오.
2018년 : 약속 파기 시도
백엔드에 불필요한 요구가 쇄도하지 않도록 API 콜을 디바운스하는 경우가 많습니다.
2018년에는 콜백(Lodash/Undercore)으로 작업하는 것이 불편하고 오류가 발생하기 쉽습니다.API 호출이 임의의 순서로 해결되기 때문에 보일러 플레이트와 동시성 문제가 발생하기 쉽습니다.
React를 염두에 두고 작은 라이브러리를 만들었습니다.대단한 약속입니다.
이것은 그것보다 복잡하지 않습니다.
const searchAPI = text => fetch('/search?text=' + encodeURIComponent(text));
const searchAPIDebounced = AwesomeDebouncePromise(searchAPI, 500);
class SearchInputAndResults extends React.Component {
state = {
text: '',
results: null,
};
handleTextChange = async text => {
this.setState({ text, results: null });
const result = await searchAPIDebounced(text);
this.setState({ result });
};
}
디버깅된 함수는 다음을 보장합니다.
- API 호출이 거부됩니다.
- 디버깅된 함수는 항상 약속을 반환한다
- 마지막 콜의 반환된 약속만이 해결됩니다.
this.setState({ result });
콜 발생합니다.
최종적으로 컴포넌트가 마운트 해제되면 다음 트릭을 추가할 수 있습니다.
componentWillUnmount() {
this.setState = () => {};
}
Observatibles(RxJ)는 입력을 비난하는 데에도 적합하지만, 더 강력한 추상화이므로 올바르게 학습/사용하기 어려울 수 있습니다.
< 2017: 콜백 디버깅을 계속 사용하시겠습니까?
여기서 중요한 것은 컴포넌트 인스턴스당 하나의 디버깅(또는 스로틀) 함수를 작성하는 것입니다.데바운스(또는 스로틀) 함수를 매번 재생성할 필요는 없습니다.또한 여러 인스턴스가 같은 디바운스 함수를 공유하지 않도록 해야 합니다.
이 답변에서 디버깅 함수를 정의하는 것은 아닙니다만, 이 답변은 다음과 같이 동작합니다._.debounce
사용자 제공 디버깅 기능뿐만 아니라 언더스코어 또는 로더쉬도 사용할 수 있습니다.
좋은 아이디어:
디버깅된 함수는 스테이트풀하기 때문에 디버깅된 함수는 컴포넌트 인스턴스마다 1개씩 작성해야 합니다.
ES6(클래스 속성): 권장
class SearchBox extends React.Component {
method = debounce(() => {
...
});
}
ES6(클래스 컨스트럭터)
class SearchBox extends React.Component {
constructor(props) {
super(props);
this.method = debounce(this.method.bind(this),1000);
}
method() { ... }
}
ES5
var SearchBox = React.createClass({
method: function() {...},
componentWillMount: function() {
this.method = debounce(this.method.bind(this),100);
},
});
JsFiddle 참조: 3개의 인스턴스가 인스턴스당 1개의 로그 엔트리를 생성합니다(글로벌하게 3개 작성).
좋지 않은 생각:
var SearchBox = React.createClass({
method: function() {...},
debouncedMethod: debounce(this.method, 100);
});
작성 시 안돼돼 during during during가 되기 하지 않습니다 왜냐하면 클래스 설명 오브젝트를 만드는 동안this
오브젝트 자체가 아닙니다. this.method
.this
context는 오브젝트 자체가 아닙니다(실제로 아직 작성 중인 BTW는 존재하지 않습니다).
좋지 않은 생각:
var SearchBox = React.createClass({
method: function() {...},
debouncedMethod: function() {
var debounced = debounce(this.method,100);
debounced();
},
});
에는 실제로 의 기능을 함수를 .this.method
. 는 매 .마다 만들고 debouncedMethod
새로 생성된 디바운스 함수는 이전 콜에 대해 아무것도 인식하지 않습니다.동일한 디버깅된 기능을 시간이 지남에 따라 재사용해야 합니다.그렇지 않으면 디버깅이 발생하지 않습니다.
좋지 않은 생각:
var SearchBox = React.createClass({
debouncedMethod: debounce(function () {...},100),
});
이건 좀 까다롭네요.
클래스의 마운트된 모든 인스턴스는 동일한 디버깅된 함수를 공유하며, 대부분의 경우 이는 사용자가 원하는 기능이 아닙니다.JsFiddle 참조: 3개의 인스턴스가 글로벌하게 1개의 로그 엔트리만 생산하고 있습니다.
클래스 수준에서 각 컴포넌트 인스턴스에서 공유되는 단일 디버깅 함수가 아닌 각 컴포넌트 인스턴스에 대해 디버깅 함수를 생성해야 합니다.
React 이벤트 풀링 처리
이것은 DOM 이벤트를 디바운스 또는 억제하는 경우가 많기 때문에 관련이 있습니다.
객체 React 서서 ( (즉 ( ) 。SyntheticEvent
콜백으로 수신한 )는 풀링됩니다(이것에 대해서는 문서화되어 있습니다).즉, 이벤트 콜백이 호출된 후 수신한 SyntheticEvent가 빈 Atribut과 함께 풀에 되돌려져 GC의 압력을 낮춥니다.
이에 SyntheticEvent
원래 콜백과 비동기적으로 속성을 설정합니다(스로틀링/오버운스하는 경우 등).이치노 , 「풀로 되돌아가다」를 할 수 .persist()
★★★★★★ 。
지속성 없음(기본 동작: 풀링된 이벤트)
onClick = e => {
alert(`sync -> hasNativeEvent=${!!e.nativeEvent}`);
setTimeout(() => {
alert(`async -> hasNativeEvent=${!!e.nativeEvent}`);
}, 0);
};
는 '비동기'로 출력합니다.hasNativeEvent=false
이치노
끈기 있게
onClick = e => {
e.persist();
alert(`sync -> hasNativeEvent=${!!e.nativeEvent}`);
setTimeout(() => {
alert(`async -> hasNativeEvent=${!!e.nativeEvent}`);
}, 0);
};
는 '비동기'로 출력합니다.hasNativeEvent=true
persist
를 사용하면 이벤트가 풀에 다시 저장되는 것을 방지할 수 있습니다.
다음 두 가지 동작을 테스트할 수 있습니다. JsFiddle
Julen의 답변을 읽고 사용 예를 들어보십시오.persist()
스로틀/차단 기능이 있습니다.
제어되지 않는 컴포넌트
이 방법을 사용할 수 있습니다.
밑줄 치다를 사용해서 를 들어보겠습니다._.debounce()
:
var SearchBox = React.createClass({
componentWillMount: function () {
this.delayedCallback = _.debounce(function (event) {
// `event.target` is accessible now
}, 1000);
},
onChange: function (event) {
event.persist();
this.delayedCallback(event);
},
render: function () {
return (
<input type="search" onChange={this.onChange} />
);
}
});
편집: 이 JSFiddle을 참조하십시오.
제어된 컴포넌트
업데이트: 위의 예에서는 제어되지 않는 구성 요소를 보여 줍니다.저는 항상 제어된 요소를 사용하고 있기 때문에 위의 다른 예를 제시하겠습니다만,event.persist()
★★★★★★★★★★★★★★★★★★」
JSFiddle도 사용할 수 있습니다.밑줄 없는 예
var SearchBox = React.createClass({
getInitialState: function () {
return {
query: this.props.query
};
},
componentWillMount: function () {
this.handleSearchDebounced = _.debounce(function () {
this.props.handleSearch.apply(this, [this.state.query]);
}, 500);
},
onChange: function (event) {
this.setState({query: event.target.value});
this.handleSearchDebounced();
},
render: function () {
return (
<input type="search"
value={this.state.query}
onChange={this.onChange} />
);
}
});
var Search = React.createClass({
getInitialState: function () {
return {
result: this.props.query
};
},
handleSearch: function (query) {
this.setState({result: query});
},
render: function () {
return (
<div id="search">
<SearchBox query={this.state.result}
handleSearch={this.handleSearch} />
<p>You searched for: <strong>{this.state.result}</strong></p>
</div>
);
}
});
React.render(<Search query="Initial query" />, document.body);
편집: 예제 및 JSFidles를 React 0.12로 업데이트
편집: Sebastien Lorber가 제기한 문제에 대처하기 위해 업데이트된 예
편집: 언더스코어를 사용하지 않고 플레인 Javascript 디바운스를 사용하는 jsfiddle로 업데이트되었습니다.
2019: 'useCallback' 리액트 후크 사용
해 본 , 저는 이 방법을 사용하고 있는 것을 되었습니다.useCallback
를 사용하는 콜의 할 수 .debounce
의 an onChange
useCallback은 의존관계 중 하나가 변경된 경우에만 변경된 콜백의 기억된 버전을 반환합니다.
빈 배열을 종속성으로 전달하면 콜백이 한 번만 호출됩니다.간단한 실장은 다음과 같습니다.
import React, { useCallback } from "react";
import { debounce } from "lodash";
const handler = useCallback(debounce(someFunction, 2000), []);
const onChange = (event) => {
// perform any event related action here
handler();
};
이게 도움이 됐으면 좋겠네요!
한동안 텍스트 입력에 고심하다가 스스로 완벽한 해결책을 찾지 못한 후 npm: react-debounce-input을 발견했습니다.
다음으로 간단한 예를 제시하겠습니다.
import React from 'react';
import ReactDOM from 'react-dom';
import {DebounceInput} from 'react-debounce-input';
class App extends React.Component {
state = {
value: ''
};
render() {
return (
<div>
<DebounceInput
minLength={2}
debounceTimeout={300}
onChange={event => this.setState({value: event.target.value})} />
<p>Value: {this.state.value}</p>
</div>
);
}
}
const appRoot = document.createElement('div');
document.body.appendChild(appRoot);
ReactDOM.render(<App />, appRoot);
DebounceInput 컴포넌트는 일반 입력 요소에 할당할 수 있는 모든 소품을 받아들입니다.코데펜으로 시험해 보다
다른 사람에게도 도움이 되고 시간도 절약됐으면 좋겠어요.
저스틴 툴크의 이 글은 매우 도움이 되었다.리액트/리듀스에서는 보다 공식적인 방법으로 몇 번 시도하면 리액트의 합성 이벤트 풀링에 의해 실패했음을 알 수 있습니다.그런 다음 내부 상태를 사용하여 입력에 변경/입력된 값을 추적하고 직후 콜백을 수행합니다.setState
이 명령어는 일부 결과를 실시간으로 보여주는 제한/예고된 감소 액션을 호출합니다.
import React, {Component} from 'react'
import TextField from 'material-ui/TextField'
import { debounce } from 'lodash'
class TableSearch extends Component {
constructor(props){
super(props)
this.state = {
value: props.value
}
this.changeSearch = debounce(this.props.changeSearch, 250)
}
handleChange = (e) => {
const val = e.target.value
this.setState({ value: val }, () => {
this.changeSearch(val)
})
}
render() {
return (
<TextField
className = {styles.field}
onChange = {this.handleChange}
value = {this.props.value}
/>
)
}
}
★★★★★★★★★★★★★★★★ debounce
은 원래 있던 것을 가지고 있어야 요.event.persist()
은 '다'로 React 16+
.
import React, { Component } from 'react';
import debounce from 'lodash/debounce'
class ItemType extends Component {
evntHandler = debounce((e) => {
console.log(e)
}, 500);
render() {
return (
<div className="form-field-wrap"
onClick={e => {
e.persist()
this.evntHandler(e)
}}>
...
</div>
);
}
}
export default ItemType;
기능 컴포넌트를 사용하면 다음과 같은 작업을 수행할 수 있습니다.
const Search = ({ getBooks, query }) => {
const handleOnSubmit = (e) => {
e.preventDefault();
}
const debouncedGetBooks = debounce(query => {
getBooks(query);
}, 700);
const onInputChange = e => {
debouncedGetBooks(e.target.value)
}
return (
<div className="search-books">
<Form className="search-books--form" onSubmit={handleOnSubmit}>
<Form.Group controlId="formBasicEmail">
<Form.Control type="text" onChange={onInputChange} placeholder="Harry Potter" />
<Form.Text className="text-muted">
Search the world's most comprehensive index of full-text books.
</Form.Text>
</Form.Group>
<Button variant="primary" type="submit">
Search
</Button>
</Form>
</div>
)
}
참고 자료 - https://gist.github.com/elijahmanor/08fc6c8468c994c844213e4a4344a709 - https://blog.revathskumar.com/2016/02/reactjs-using-debounce-in-react-components.html
이라면 해결 즉, "DOM"을 사용하면 .사용만 하면 됩니다.ref
. 이 경우 밑줄이 필요합니다.
class Item extends React.Component {
constructor(props) {
super(props);
this.saveTitle = _.throttle(this.saveTitle.bind(this), 1000);
}
saveTitle(){
let val = this.inputTitle.value;
// make the ajax call
}
render() {
return <input
ref={ el => this.inputTitle = el }
type="text"
defaultValue={this.props.title}
onChange={this.saveTitle} />
}
}
이 솔루션은 후크 기반(Typescript에 기재)입니다.
훅이useDebouncedValue
★★★★★★★★★★★★★★★★★」useDebouncedCallback
번째 - 아, 아, 지만 -useDebouncedValue
예를 들어 검색 상자가 있지만 사용자가 0.5초 동안 입력을 중지한 후 서버에 검색 결과를 요청하려고 합니다.
function SearchInput() {
const [realTimeValue, setRealTimeValue] = useState('');
const debouncedValue = useDebouncedValue(realTimeValue, 500); // this value will pick real time value, but will change it's result only when it's seattled for 500ms
useEffect(() => {
// this effect will be called on seattled values
api.fetchSearchResults(debouncedValue);
}, [debouncedValue])
return <input onChange={event => setRealTimeValue(event.target.value)} />
}
실행
import { useState, useEffect } from "react";
export function useDebouncedValue<T>(input: T, time = 500) {
const [debouncedValue, setDebouncedValue] = useState(input);
// every time input value has changed - set interval before it's actually commited
useEffect(() => {
const timeout = setTimeout(() => {
setDebouncedValue(input);
}, time);
return () => {
clearTimeout(timeout);
};
}, [input, time]);
return debouncedValue;
}
번째 ★★★useDebouncedCallback
컴포넌트 범위 내에서 'deverged' 함수를 생성할 뿐입니다.
클릭을 멈춘 지 500ms 후에 경보가 표시되는 버튼이 있는 컴포넌트가 있다고 칩시다.
function AlertButton() {
function showAlert() {
alert('Clicking has seattled');
}
const debouncedShowAlert = useDebouncedCallback(showAlert, 500);
return <button onClick={debouncedShowAlert}>Click</button>
}
구현(도움말로서 lodash/debounce를 사용하고 있음)
import debounce from 'lodash/debounce';
import { useMemo } from 'react';
export function useDebouncedCallback<T extends (...args: any) => any>(callback: T, wait?: number) {
const debouncedCallback = useMemo(() => debounce(callback, wait), [callback, wait]);
return debouncedCallback;
}
리액트 훅을 사용한 간단한 접근법이 있습니다.
1단계 : 검색된 텍스트를 유지할 상태를 정의합니다.
const [searchTerm, setSearchTerm] = useState('')
2단계 : useEffect를 사용하여 검색어 변경 내용 캡처
useEffect(() => {
const delayDebounceFn = setTimeout(() => {
if (searchTerm) {
// write your logic here
}
}, 400)
return () => clearTimeout(delayDebounceFn)
}, [searchTerm])
3단계 : 입력변경을 처리하는 함수를 작성한다.
function handleInputChange(value) {
if (value) {
setSearchTerm(value)
}
}
이상입니다! 이 메서드를 필요에 따라 호출합니다.
게 요.use-debounce
후크에서 사용할 수 패키지입니다.JS »
패키지의 README에서:
import { useDebounce } from 'use-debounce';
export default function Input() {
const [text, setText] = useState('Hello');
const [value] = useDebounce(text, 1000);
return (
<div>
<input
defaultValue={'Hello'}
onChange={(e) => {
setText(e.target.value);
}}
/>
<p>Actual value: {text}</p>
<p>Debounce value: {value}</p>
</div>
);
}
에서 알 수 변수 .value
1 ( 1000 ) 。
여기엔 이미 많은 좋은 정보들이 있지만, 간결하게 말하자면.난 이거면 되는데...
import React, {Component} from 'react';
import _ from 'lodash';
class MyComponent extends Component{
constructor(props){
super(props);
this.handleChange = _.debounce(this.handleChange.bind(this),700);
};
레덕스를 사용하는 경우 미들웨어를 사용하면 매우 우아한 방법으로 이 작업을 수행할 수 있습니다. '어울릴 것 같다'를 할 수 .Debounce
★★★★★★★★★★★★★★★★★★:
var timeout;
export default store => next => action => {
const { meta = {} } = action;
if(meta.debounce){
clearTimeout(timeout);
timeout = setTimeout(() => {
next(action)
}, meta.debounce)
}else{
next(action)
}
}
그런 다음 다음과 같이 작업 작성자에 디버깅을 추가할 수 있습니다.
export default debouncedAction = (payload) => ({
type : 'DEBOUNCED_ACTION',
payload : payload,
meta : {debounce : 300}
}
실제로 미들웨어는 이미 준비되어 있습니다.NPM에서 이 작업을 수행할 수 있습니다.
ES6 CLASS 및 React 15.x.x & lodash.debounce Im을 사용하면 내부에서 이 바인딩이 손실되므로 여기서 React의 참조를 사용합니다.
class UserInput extends React.Component {
constructor(props) {
super(props);
this.state = {
userInput: ""
};
this.updateInput = _.debounce(this.updateInput, 500);
}
updateInput(userInput) {
this.setState({
userInput
});
//OrderActions.updateValue(userInput);//do some server stuff
}
render() {
return ( <div>
<p> User typed: {
this.state.userInput
} </p>
<input ref = "userValue" onChange = {() => this.updateInput(this.refs.userValue.value) } type = "text" / >
</div>
);
}
}
ReactDOM.render( <
UserInput / > ,
document.getElementById('root')
);
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.5/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Lodash debounce https://lodash.com/docs/4.17.5#debounce 메서드를 사용할 수 있습니다.그것은 간단하고 효과적이다.
import * as lodash from lodash;
const update = (input) => {
// Update the input here.
console.log(`Input ${input}`);
}
const debounceHandleUpdate = lodash.debounce((input) => update(input), 200, {maxWait: 200});
doHandleChange() {
debounceHandleUpdate(input);
}
다음 방법을 사용하여 데바운스 방식을 취소할 수도 있습니다.
this.debounceHandleUpdate.cancel();
도움이 되길 바랍니다.건배!!
참고:
PoC의 다른 실장은 다음과 같습니다.
- 비난하기 위한 라이브러리(예를 들어 로다시)가 없는
- React Hooks API 사용
도움이 되었으면 합니다:)
import React, { useState, useEffect, ChangeEvent } from 'react';
export default function DebouncedSearchBox({
inputType,
handleSearch,
placeholder,
debounceInterval,
}: {
inputType?: string;
handleSearch: (q: string) => void;
placeholder: string;
debounceInterval: number;
}) {
const [query, setQuery] = useState<string>('');
const [timer, setTimer] = useState<NodeJS.Timer | undefined>();
useEffect(() => {
if (timer) {
clearTimeout(timer);
}
setTimer(setTimeout(() => {
handleSearch(query);
}, debounceInterval));
}, [query]);
const handleOnChange = (e: ChangeEvent<HTMLInputElement>): void => {
setQuery(e.target.value);
};
return (
<input
type={inputType || 'text'}
className="form-control"
placeholder={placeholder}
value={query}
onChange={handleOnChange}
/>
);
}
2022 - useEffect 후크 사용
때 가장 좋은 은 '''를 하는 것입니다.useEffect
useEffect
그럼 비동기 이벤트에 대한 응답으로 상태를 변경할 수 있는 함수를 설정할 수 있습니다.useEffect를 사용하다
후크에서 함수를 반환하면 반환된 함수는 후크가 다시 호출되기 전에 호출됩니다.이것에 의해, 이전의 타임 아웃을 취소해, 사실상 기능을 파기할 수 있습니다.
예
두 상태가 .value
★★★★★★★★★★★★★★★★★」tempValue
★★tempValue
.useEffect
으로 1000밀리초 복사를 위한 를 합니다.tempValue
value
.
후크는 타이머 설정을 해제하는 함수를 반환합니다.후크가 다시 호출되면(즉, 다른 키를 누르면) 타임아웃이 취소되고 재설정됩니다.
const DebounceDemo = () => {
const [value, setValue] = useState();
const [tempValue, setTempValue] = useState();
// This hook will set a 1000 ms timer to copy tempValue into value
// If the hook is called again, the timer will be cancelled
// This creates a debounce
useEffect(
() => {
// Wait 1000ms before copying the value of tempValue into value;
const timeout = setTimeout(() => {
setValue(tempValue);
}, 1000);
// If the hook is called again, cancel the previous timeout
// This creates a debounce instead of a delay
return () => clearTimeout(timeout);
},
// Run the hook every time the user makes a keystroke
[tempValue]
)
// Here we create an input to set tempValue.
// value will be updated 1000 ms after the hook is last called,
// i.e after the last user keystroke.
return (
<>
<input
onChange={
({ target }) => setTempValue(target.value)
}
/>
<p>{ value }</p>
</>
)
}
이제 2019년 말에 React and React Native를 위한 또 다른 솔루션이 있습니다.
<input>
<Debounce ms={500}>
<List/>
</Debounce>
컴포넌트이며 사용하기 쉽고 소형이며 Widley 지원
예:
import React from 'react';
import Debounce from 'react-debounce-component';
class App extends React.Component {
constructor (props) {
super(props);
this.state = {value: 'Hello'}
}
render () {
return (
<div>
<input value={this.state.value} onChange={(event) => {this.setState({value: event.target.value})}}/>
<Debounce ms={1000}>
<div>{this.state.value}</div>
</Debounce>
</div>
);
}
}
export default App;
* 이 컴포넌트의 작성자입니다.
이 질문에서는 현재 사용하고 있는 접근법에 대한 답변을 찾을 수 없습니다.이 질문에서는 사용 사례에 가장 적합한 대체 솔루션을 제안하고 싶습니다.
훅를 사용하고 경우 리액트 훅 lib는 리액트 훅입니다.react-use
, 훅이라고 하는 useDebounce()
꽤 우아한 방식으로 규탄 논리를 실행했습니다.
const [query, setQuery] = useState('');
useDebounce(
() => {
emitYourOnDebouncedSearchEvent(query);
},
2000,
[query]
);
return <input onChange={({ currentTarget }) => setQuery(currentTarget.value)} />
자세한 내용은 lib의 github 페이지를 직접 확인하십시오.
https://github.com/streamich/react-use/blob/master/docs/useDebounce.md
2021년 6월부터는 xnimorz 솔루션을 간단하게 구현할 수 있습니다.https://github.com/xnimorz/use-debounce
import { useState, useEffect, useRef } from "react";
// Usage
function App() {
// State and setters for ...
// Search term
const [searchTerm, setSearchTerm] = useState("");
// API search results
const [results, setResults] = useState([]);
// Searching status (whether there is pending API request)
const [isSearching, setIsSearching] = useState(false);
// Debounce search term so that it only gives us latest value ...
// ... if searchTerm has not been updated within last 500ms.
// The goal is to only have the API call fire when user stops typing ...
// ... so that we aren't hitting our API rapidly.
const debouncedSearchTerm = useDebounce(searchTerm, 500);
// Effect for API call
useEffect(
() => {
if (debouncedSearchTerm) {
setIsSearching(true);
searchCharacters(debouncedSearchTerm).then((results) => {
setIsSearching(false);
setResults(results);
});
} else {
setResults([]);
setIsSearching(false);
}
},
[debouncedSearchTerm] // Only call effect if debounced search term changes
);
return (
<div>
<input
placeholder="Search Marvel Comics"
onChange={(e) => setSearchTerm(e.target.value)}
/>
{isSearching && <div>Searching ...</div>}
{results.map((result) => (
<div key={result.id}>
<h4>{result.title}</h4>
<img
src={`${result.thumbnail.path}/portrait_incredible.${result.thumbnail.extension}`}
/>
</div>
))}
</div>
);
}
// API search function
function searchCharacters(search) {
const apiKey = "f9dfb1e8d466d36c27850bedd2047687";
return fetch(
`https://gateway.marvel.com/v1/public/comics?apikey=${apiKey}&titleStartsWith=${search}`,
{
method: "GET",
}
)
.then((r) => r.json())
.then((r) => r.data.results)
.catch((error) => {
console.error(error);
return [];
});
}
// Hook
function useDebounce(value, delay) {
// State and setters for debounced value
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(
() => {
// Update debounced value after delay
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
// Cancel the timeout if value changes (also on delay change or unmount)
// This is how we prevent debounced value from updating if value is changed ...
// .. within the delay period. Timeout gets cleared and restarted.
return () => {
clearTimeout(handler);
};
},
[value, delay] // Only re-call effect if value or delay changes
);
return debouncedValue;
}
외부 의존이 필요 없는 깔끔한 솔루션:
및 useEffectReact를 합니다.setTimeout
clearTimeout
★★★★★★ 。
최근 반응과 lodash를 가진 또 다른 변종일 뿐입니다.
class Filter extends Component {
static propTypes = {
text: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired
}
state = {
initialText: '',
text: ''
}
constructor (props) {
super(props)
this.setText = this.setText.bind(this)
this.onChange = _.fp.debounce(500)(this.onChange.bind(this))
}
static getDerivedStateFromProps (nextProps, prevState) {
const { text } = nextProps
if (text !== prevState.initialText) {
return { initialText: text, text }
}
return null
}
setText (text) {
this.setState({ text })
this.onChange(text)
}
onChange (text) {
this.props.onChange(text)
}
render () {
return (<input value={this.state.text} onChange={(event) => this.setText(event.target.value)} />)
}
}
해봤어?
function debounce(fn, delay) {
var timer = null;
return function() {
var context = this,
args = arguments;
clearTimeout(timer);
timer = setTimeout(function() {
fn.apply(context, args);
}, delay);
};
}
var SearchBox = React.createClass({
render: function() {
return <input type="search" name="p" onChange={this.handleOnChange} />;
},
handleOnChange: function(event) {
debounce(\\ Your handleChange code , 200);
}
});
handleOnChange를 데바운스()로 랩하는 것이 아니라 데바운스 내의 콜백함수 내에서 에이잭스콜을 랩하여 이벤트개체를 파괴하지 마세요.예를 들어 다음과 같습니다.
handleOnChange: function (event) {
debounce(
$.ajax({})
, 250);
}
여기 제가 생각해낸 예시가 있습니다. 다른 클래스를 디바운서로 감싸는 것입니다.데코레이터/고차원으로 만들기에 적합합니다.
export class DebouncedThingy extends React.Component {
static ToDebounce = ['someProp', 'someProp2'];
constructor(props) {
super(props);
this.state = {};
}
// On prop maybe changed
componentWillReceiveProps = (nextProps) => {
this.debouncedSetState();
};
// Before initial render
componentWillMount = () => {
// Set state then debounce it from here on out (consider using _.throttle)
this.debouncedSetState();
this.debouncedSetState = _.debounce(this.debouncedSetState, 300);
};
debouncedSetState = () => {
this.setState(_.pick(this.props, DebouncedThingy.ToDebounce));
};
render() {
const restOfProps = _.omit(this.props, DebouncedThingy.ToDebounce);
return <Thingy {...restOfProps} {...this.state} />
}
}
여기 @Abra의 접근방식을 사용한 스니펫을 함수의 컴포넌트로 정리합니다(UI에는 패브릭을 사용합니다.단순한 버튼으로 대체해 주세요).
import React, { useCallback } from "react";
import { debounce } from "lodash";
import { PrimaryButton, DefaultButton } from 'office-ui-fabric-react/lib/Button';
const debounceTimeInMS = 2000;
export const PrimaryButtonDebounced = (props) => {
const debouncedOnClick = debounce(props.onClick, debounceTimeInMS, { leading: true });
const clickHandlerDebounced = useCallback((e, value) => {
debouncedOnClick(e, value);
},[]);
const onClick = (e, value) => {
clickHandlerDebounced(e, value);
};
return (
<PrimaryButton {...props}
onClick={onClick}
/>
);
}
을 사용하다다 solved 。setTimeout
★★★★★★★★★★★★★★★★★」clearTimeout
적용할 수 있는 예를 제시하겠습니다.
import React, { Component } from 'react'
const DEBOUNCE_TIME = 500
class PlacesAutocomplete extends Component {
debounceTimer = null;
onChangeHandler = (event) => {
// Clear the last registered timer for the function
clearTimeout(this.debounceTimer);
// Set a new timer
this.debounceTimer = setTimeout(
// Bind the callback function to pass the current input value as arg
this.getSuggestions.bind(null, event.target.value),
DEBOUNCE_TIME
)
}
// The function that is being debounced
getSuggestions = (searchTerm) => {
console.log(searchTerm)
}
render() {
return (
<input type="text" onChange={this.onChangeHandler} />
)
}
}
export default PlacesAutocomplete
독자적인 기능 컴포넌트로 리팩터링할 수도 있습니다.
import React from 'react'
function DebouncedInput({ debounceTime, callback}) {
let debounceTimer = null
return (
<input type="text" onChange={(event) => {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(
callback.bind(null, event.target.value),
debounceTime
)
}} />
)
}
export default DebouncedInput
사용법은 다음과 같습니다.
import React, { Component } from 'react'
import DebouncedInput from '../DebouncedInput';
class PlacesAutocomplete extends Component {
debounceTimer = null;
getSuggestions = (searchTerm) => {
console.log(searchTerm)
}
render() {
return (
<DebouncedInput debounceTime={500} callback={this.getSuggestions} />
)
}
}
export default PlacesAutocomplete
이 솔루션에서는 추가 lib가 필요하지 않으며 사용자가 Enter 키를 눌렀을 때도 부팅됩니다.
const debounce = (fn, delay) => {
let timer = null;
return function() {
const context = this,
args = arguments;
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(context, args);
}, delay);
};
}
const [search, setSearch] = useState('');
const [searchFor, setSearchFor] = useState(search);
useEffect(() => {
console.log("Search:", searchFor);
}, [searchFor]);
const fireChange = event => {
const { keyCode } = event;
if (keyCode === 13) {
event.preventDefault();
setSearchFor(search);
}
}
const changeSearch = event => {
const { value } = event.target;
setSearch(value);
debounceSetSearchFor(value);
};
const debounceSetSearchFor = useCallback(debounce(function(value) {
setSearchFor(value);
}, 250), []);
입력은 다음과 같습니다.
<input value={search} onKeyDown={fireChange} onChange={changeSearch} />
후크:
import {useState} from "react";
const useDebounce = ({defaultTimeout = 250, defaultIdentifier = 'default'} = {}) => {
const [identifiers, setIdentifiers] = useState({[defaultIdentifier]: null});
return ({fn = null, identifier = defaultIdentifier, timeout = defaultTimeout} = {}) => {
if (identifiers.hasOwnProperty(identifier)) clearTimeout(identifiers[identifier]);
setIdentifiers({...identifiers, [identifier]: setTimeout(fn, timeout)});
};
};
export default useDebounce;
또, 다음과 같은 장소(동일한 파일내의 식별자 사용)에서도 사용할 수 있습니다.
const debounce = useDebounce();
const handlerA = () => {
debounce({fn: () => console.log('after 2000ms of last call with identifier A'), identifier: 'A', timeout: 2000});
};
const handlerB = () => {
debounce({fn: () => console.log('after 1500ms of last call with identifier B'), identifier: 'B', timeout: 1500});
};
https://www.npmjs.com/package/use-debouncehttpswww.npmjs.com/package/
use-debounce
import { useDebouncedCallback } from 'use-debounce';
function Input({ defaultValue }) {
const [value, setValue] = useState(defaultValue);
const debounced = useDebouncedCallback(
(value) => {
setValue(value);
},
// delay
1000
);
return (
<div>
<input defaultValue={defaultValue} onChange={(e) => debounced(e.target.value)} />
<p>Debounced value: {value}</p>
</div>
);
}
에 대한 로 이 되었는데, 문제가 : 만약 이 이 문제를 .handleOnChange
target으로부터의 , 「이벤트 타겟」의 값을 합니다.cannot read property value of null
또는 그러한 에러입니다.가 있었습니다.this
디버깅된 함수에 들어가 있습니다. 왜냐하면 저는 가변적인 동작을 하고 있기 때문입니다.다음은 제 사용 사례에 적합한 솔루션입니다. 따라서 이 문제를 접하게 될 경우를 대비해서 여기에 남겨두겠습니다.
// at top of file:
var myAction = require('../actions/someAction');
// inside React.createClass({...});
handleOnChange: function (event) {
var value = event.target.value;
var doAction = _.curry(this.context.executeAction, 2);
// only one parameter gets passed into the curried function,
// so the function passed as the first parameter to _.curry()
// will not be executed until the second parameter is passed
// which happens in the next function that is wrapped in _.debounce()
debouncedOnChange(doAction(myAction), value);
},
debouncedOnChange: _.debounce(function(action, value) {
action(value);
}, 300)
언급URL : https://stackoverflow.com/questions/23123138/how-to-perform-debounce
'source' 카테고리의 다른 글
Larabel에서 이 작업을 수행하는 방법, 서브쿼리: (0) | 2022.10.15 |
---|---|
Javascript - 내부가 없는 컨테이너 요소에 HTML 추가HTML (0) | 2022.10.15 |
Java SE와 Java EE의 주요 차이점은 무엇입니까? (0) | 2022.10.15 |
외부 리액트 컴포넌트 클릭 검출 (0) | 2022.10.15 |
커밋되지 않은 트랜잭션이 특정 고유 키를 SQL에 삽입하려고 하는지 확인하는 방법 (0) | 2022.10.15 |