Javascript 在React.js中执行去盎司
如何在React.js中执行去盎司 我想把零钱去掉 我试过使用Javascript 在React.js中执行去盎司,javascript,reactjs,Javascript,Reactjs,如何在React.js中执行去盎司 我想把零钱去掉 我试过使用debounce(this.handleOnChange,200),但不起作用 function debounce(fn, delay) { var timer = null; return function() { var context = this, args = arguments; clearTimeout(timer); timer = setTimeout(function()
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
}
});
功能去抖动(fn,延迟){
var定时器=null;
返回函数(){
var context=this,
args=参数;
清除超时(计时器);
计时器=设置超时(函数(){
fn.应用(上下文,args);
},延误);
};
}
var SearchBox=React.createClass({
render:function(){
返回;
},
更改:功能(事件){
//打ajax电话
}
});
与其将handleOnChange包装在debounce()中,为什么不将ajax调用包装在debounce中的回调函数中,从而不破坏事件对象呢。比如说:
handleOnChange: function (event) {
debounce(
$.ajax({})
, 250);
}
非受控部件
您可以使用
下面是一个使用下划线的..debounce()
的示例:
var SearchBox=React.createClass({
componentWillMount:函数(){
this.delayedCallback=\ u0.debounce(函数(事件){
//现在可以访问'event.target'
}, 1000);
},
onChange:函数(事件){
event.persist();
此.delayedCallback(事件);
},
渲染:函数(){
返回(
);
}
});
编辑:参见
受控元件 更新:上面的示例显示了一个。我一直在使用受控元素,所以这里是上面的另一个示例,但没有使用
event.persist()
“trickery”
A也是
var SearchBox=React.createClass({
getInitialState:函数(){
返回{
查询:this.props.query
};
},
componentWillMount:函数(){
this.handlesearchdebound=\ u0.debounce(函数(){
this.props.handleSearch.apply(this[this.state.query]);
}, 500);
},
onChange:函数(事件){
this.setState({query:event.target.value});
这个.handlesearchdebound();
},
渲染:函数(){
返回(
);
}
});
var Search=React.createClass({
getInitialState:函数(){
返回{
结果:this.props.query
};
},
handleSearch:函数(查询){
this.setState({result:query});
},
渲染:函数(){
返回(
您搜索了:{this.state.result}
);
}
});
React.render(,document.body);
编辑:更新了示例和JSFiddles以响应0.12 编辑:更新示例以解决Sebastien Lorber提出的问题 编辑:使用不使用下划线且使用纯javascript去Bouncing的JSFIDLE进行更新。2019:尝试挂钩+承诺去Bouncing 这是我解决这个问题的最新版本。我将使用:
- 要解除异步函数的隔振
- 将去抖动的函数存储到组件中
- 将结果输入到我的组件中
// 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>
);
};
去抖动功能可确保:
- API调用将被取消公告
- 取消公告函数总是返回一个承诺
- 只有最后一个电话的回复承诺才能解决问题
- 单个
this.setState({result})代码>将在每个API调用中发生
componentWillUnmount() {
this.setState = () => {};
}
请注意,可观测值(RxJS)也非常适合于去抖动输入,但它是一种更强大的抽象,可能更难正确学习/使用
<2017:仍要使用回调去抖动? 这里的重要部分是为每个组件实例创建一个单独的去抖动(或节流)函数。您不希望每次都重新创建去抖动(或节流)函数,也不希望多个实例共享同一个去抖动函数 我并没有在这个答案中定义去抖动功能,因为它实际上并不相关,但这个答案可以很好地使用下划线或lodash的
.debounce
,以及任何用户提供的去抖动功能
好主意: 因为取消公告的函数是有状态的,所以我们必须为每个组件实例创建一个取消公告的函数 ES6(类别属性):推荐
class SearchBox extends React.Component {
method = debounce(() => {
...
});
}
ES6(类构造函数)
ES5
var SearchBox = React.createClass({
method: function() {...},
componentWillMount: function() {
this.method = debounce(this.method.bind(this),100);
},
});
请参阅:3个实例为每个实例生成1个日志条目(即全局生成3个)
这不是个好主意: 它不起作用,因为在类描述对象创建过程中,
这个
不是自己创建的对象this.method
不会返回您期望的结果,因为this
上下文不是对象本身(实际上还不存在,因为它刚刚被创建)
这不是个好主意: 这一次,您正在有效地创建一个取消公告的函数,该函数调用您的
This.method
。问题是每次调用debouncedMethod
时都要重新创建它,因此新创建的debounce函数对以前的调用一无所知!随着时间的推移,必须重复使用相同的去抖动功能,否则将不会发生去抖动
这不是个好主意: 这有点棘手 该类的所有已装入实例将共享同一个取消公告的函数,通常这不是您想要的!。请参阅:3个实例全局只生成1个日志条目 您必须为每个组件实例创建一个取消公告的函数,而不是在类级别创建一个由每个组件实例共享的取消公告的函数
注意React的事件池 这是相关的,因为我们经常希望消除或限制DOM事件
class SearchBox extends React.Component {
constructor(props) {
super(props);
this.method = debounce(this.method.bind(this),1000);
}
method() { ... }
}
var SearchBox = React.createClass({
method: function() {...},
componentWillMount: function() {
this.method = debounce(this.method.bind(this),100);
},
});
var SearchBox = React.createClass({
method: function() {...},
debouncedMethod: debounce(this.method, 100);
});
var SearchBox = React.createClass({
method: function() {...},
debouncedMethod: function() {
var debounced = debounce(this.method,100);
debounced();
},
});
var SearchBox = React.createClass({
debouncedMethod: debounce(function () {...},100),
});
onClick = e => {
alert(`sync -> hasNativeEvent=${!!e.nativeEvent}`);
setTimeout(() => {
alert(`async -> hasNativeEvent=${!!e.nativeEvent}`);
}, 0);
};
onClick = e => {
e.persist();
alert(`sync -> hasNativeEvent=${!!e.nativeEvent}`);
setTimeout(() => {
alert(`async -> hasNativeEvent=${!!e.nativeEvent}`);
}, 0);
};
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} />
}
}
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} />
}
}
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}
}
updateUserProfileField(fieldName) {
const handler = throttle(value => {
console.log(fieldName, value);
}, 400);
return evt => handler(evt.target.value.trim());
}
<input onChange={this.updateUserProfileField("givenName").bind(this)}/>
updateUserProfileField(fieldName) {
return evt => throttle(value => {
console.log(fieldName, value);
}, 400)(evt.target.value.trim());
}
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}
/>
)
}
}
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);
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();
import React, {Component} from 'react';
import _ from 'lodash';
class MyComponent extends Component{
constructor(props){
super(props);
this.handleChange = _.debounce(this.handleChange.bind(this),700);
};
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<T extends (...args: any[]) => any>(time: number, func: T): (...funcArgs: Parameters<T>) => Promise<ReturnType<T>> {
let timeout: Timeout;
return (...args: Parameters<T>): Promise<ReturnType<T>> => new Promise((resolve) => {
clearTimeout(timeout);
timeout = setTimeout(() => {
resolve(func(...args));
}, time)
});
}
export class debouncedMethod<T>{
constructor(method:T, debounceTime:number){
this._method = method;
this._debounceTime = debounceTime;
}
private _method:T;
private _timeout:number;
private _debounceTime:number;
public invoke:T = ((...args:any[])=>{
this._timeout && window.clearTimeout(this._timeout);
this._timeout = window.setTimeout(()=>{
(this._method as any)(...args);
},this._debounceTime);
}) as any;
}
var foo = new debouncedMethod((name,age)=>{
console.log(name,age);
},500);
foo.invoke("john",31);
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>
);
}
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();
};
<input>
<Debounce ms={500}>
<List/>
</Debounce>
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;
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}
/>
);
}
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, { 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
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);
}
});
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} />
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;
}
function AlertButton() {
function showAlert() {
alert('Clicking has seattled');
}
const debouncedShowAlert = useDebouncedCallback(showAlert, 500);
return <button onClick={debouncedShowAlert}>Click</button>
}
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;
}
const PageOne = () => {
const [requesting, setRequesting] = useState(false);
useEffect(() => {
return () => {
setRequesting(false);
};
}, [requesting]);
const onDebounce = (e) => {
if (requesting === true) {
e.preventDefault();
}
// ACTIONS
setLoading(true);
};
return (
<div>
<button onClick={onDebounce}>Requesting data</button>
</div>
)
}
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});
};
const [query, setQuery] = useState('');
useDebounce(
() => {
emitYourOnDebouncedSearchEvent(query);
},
2000,
[query]
);
return <input onChange={({ currentTarget }) => setQuery(currentTarget.value)} />