질문 : React.js에서 디 바운스 수행
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
}
});
답변
이것은 내가이 문제를 해결하는 방법의 가장 최신 버전입니다. 다음을 사용합니다.
- 비동기 함수를 디 바운스하는 awesome-debounce-promise
- 디 바운스 된 함수를 컴포넌트에 저장하는 use-constant
- 내 구성 요소에 결과를 가져 오기 위해 react-async-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 문서를 읽어야합니다.
백엔드가 쓸모없는 요청으로 넘쳐나는 것을 피하기 위해 종종 API 호출을 디 바운스하려고합니다.
2018 년에는 콜백 (Lodash / Underscore) 작업이 나쁘고 오류가 발생하기 쉽습니다. 임의의 순서로 해결되는 API 호출로 인해 상용구 및 동시성 문제가 발생하기 쉽습니다.
나는 당신의 고통을 해결하기 위해 React를 염두에두고 작은 라이브러리를 만들었습니다 : awesome-debounce-promise .
이것은 그것보다 더 복잡해서는 안됩니다 :
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 });
API 호출마다 발생합니다.
결국 구성 요소가 마운트 해제되면 다른 트릭을 추가 할 수 있습니다.
componentWillUnmount() {
this.setState = () => {};
}
Observable (RxJS)도 입력 디 바운싱에 적합 할 수 있지만 올바르게 배우고 사용하기 어려울 수있는 더 강력한 추상화입니다.
여기서 중요한 부분은 구성 요소 인스턴스 당 단일 디 바운스 (또는 조절) 함수를 만드는 것 입니다. 매번 디 바운스 (또는 스로틀) 기능을 다시 생성하고 싶지 않으며 여러 인스턴스가 동일한 디 바운스 된 기능을 공유하는 것을 원하지 않습니다.
정말 관련이 아니에요 나는이 대답에 디 바운싱 기능을 정의하고 있지 않다, 그러나이 대답은 완벽하게 잘 작동합니다 _.debounce
밑줄 또는 lodash의,뿐만 아니라 사용자가 제공 한 디 바운싱 기능.
디 바운스 된 함수는 상태 저장이므로 구성 요소 인스턴스 당 하나의 디 바운스 된 함수 를 만들어야합니다.
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);
});
작동하지 않습니다. 클래스 설명 객체 생성 중에 this
자체적으로 생성 된 객체가 아니기 때문입니다. this.method
this
컨텍스트가 객체 자체가 아니기 때문에 예상 한 것을 반환하지 않습니다 (실제로 실제로 존재하지 않는 BTW는 방금 생성됨).
var SearchBox = React.createClass({
method: function() {...},
debouncedMethod: function() {
var debounced = debounce(this.method,100);
debounced();
},
});
this.method
를 호출하는 디 바운스 된 함수를 효과적으로 생성하고 있습니다. 문제는 모든 debouncedMethod
호출에서 다시 생성하므로 새로 생성 된 debounce 함수는 이전 호출에 대해 아무것도 알지 못합니다! 시간이 지남에 따라 동일한 디 바운스 된 함수를 재사용해야합니다. 그렇지 않으면 디 바운싱이 발생하지 않습니다.
var SearchBox = React.createClass({
debouncedMethod: debounce(function () {...},100),
});
이것은 여기서 약간 까다 롭습니다.
클래스의 마운트 된 모든 인스턴스는 동일한 디 바운스 된 기능을 공유하며 대부분의 경우 이것이 원하는 것이 아닙니다!. JsFiddle 참조 : 3 개의 인스턴스가 전 세계적으로 1 개의 로그 항목 만 생성합니다.
각 구성 요소 인스턴스에서 공유하는 클래스 수준의 단일 디 바운스 함수가 아닌 각 구성 요소 인스턴스에 대해 디 바운스 된 함수를 만들어야합니다.
이것은 우리가 종종 DOM 이벤트를 디 바운스하거나 스로틀하기를 원하기 때문에 관련됩니다.
React에서는 콜백에서 수신하는 이벤트 객체 (예 : SyntheticEvent
)가 풀링됩니다 (이제 문서화 됨 ). 즉, 이벤트 콜백이 호출 된 후 수신 한 SyntheticEvent가 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);
};
제 2 회 (비동기)가 인쇄됩니다 hasNativeEvent=true
때문에이 persist
하면 풀의 이벤트 등을 넣어 피할 수 있습니다.
다음 두 가지 동작을 테스트 할 수 있습니다. JsFiddle
스로틀 / 디 바운스 함수와 함께 persist()
를 사용하는 예제에 대한 Julen의 답변 을 읽으십시오.
출처 : https://stackoverflow.com/questions/23123138/perform-debounce-in-react-js
'프로그래밍 언어 > HTML,CSS,JS' 카테고리의 다른 글
Node.js에서 npm 모듈을 제거하는 방법 (0) | 2021.07.15 |
---|---|
<br/>를 사용하지 않고 CSS에서 줄 바꿈하는 방법 (0) | 2021.07.15 |
jQuery .css()를 사용하여 !important를 적용하는 방법 (0) | 2021.07.15 |
AngularJS에서 $ scope. $ watch와 $ scope. $ apply를 사용하는 방법 (0) | 2021.07.14 |
div가 나머지 화면 공간의 높이를 채우도록 하는 방법 (0) | 2021.07.13 |