39

我正在尝试将使用 lodash 的去抖动添加到从输入 onChange 事件调用的搜索函数中。下面的代码生成一个类型错误'函数是预期的',我理解这是因为 lodash 需要一个函数。这样做的正确方法是什么,可以全部内联吗?到目前为止,我已经尝试了几乎所有关于 SO 的示例,但均无济于事。

search(e){
 let str = e.target.value;
 debounce(this.props.relay.setVariables({ query: str }), 500);
},
4

12 回答 12

37

debounce 函数可以在 JSX 中内联传递或直接设置为类方法,如下所示:

search: _.debounce(function(e) {
  console.log('Debounced Event:', e);
}, 1000)

小提琴: https ://jsfiddle.net/woodenconsulting/69z2wepo/36453/

如果您使用的是 es2015+,您可以直接在您的constructor或生命周期方法(如componentWillMount.

例子:

class DebounceSamples extends React.Component {
  constructor(props) {
    super(props);

    // Method defined in constructor, alternatively could be in another lifecycle method
    // like componentWillMount
    this.search = _.debounce(e => {
      console.log('Debounced Event:', e);
    }, 1000);
  }

  // Define the method directly in your class
  search = _.debounce((e) => {
    console.log('Debounced Event:', e);
  }, 1000)
}
于 2016-03-29T21:43:32.863 回答
22

使用功能性反应组件尝试使用useCallback. useCallback记住你的去抖动函数,这样它就不会在组件重新渲染时一次又一次地重新创建。没有useCallback去抖动功能将不会与下一次击键同步。

`

import {useCallback} from 'react';
import _debounce from 'lodash/debounce';
import axios from 'axios';

function Input() {
    const [value, setValue] = useState('');

    const debounceFn = useCallback(_debounce(handleDebounceFn, 1000), []);

    function handleDebounceFn(inputValue) {
        axios.post('/endpoint', {
          value: inputValue,
        }).then((res) => {
          console.log(res.data);
        });
    }


    function handleChange (event) {
        setValue(event.target.value);
        debounceFn(event.target.value);
    };

    return <input value={value} onChange={handleChange} />
}

`

于 2021-06-11T17:29:32.843 回答
21

这就是我在谷歌搜索一整天后必须这样做的方式。

const MyComponent = (props) => {
  const [reload, setReload] = useState(false);

  useEffect(() => {
    if(reload) { /* Call API here */ }
  }, [reload]);

  const callApi = () => { setReload(true) }; // You might be able to call API directly here, I haven't tried
  const [debouncedCallApi] = useState(() => _.debounce(callApi, 1000));

  function handleChange() { 
    debouncedCallApi(); 
  }

  return (<>
    <input onChange={handleChange} />
  </>);
}
于 2019-08-05T23:21:25.700 回答
3

这不是那么容易的问题

一方面,要解决您遇到的错误,您需要将您包装setVariables在函数中:

 search(e){
  let str = e.target.value;
  _.debounce(() => this.props.relay.setVariables({ query: str }), 500);
}

另一方面,我相信去抖动逻辑必须封装在 Relay 中。

于 2016-03-29T20:14:01.730 回答
2

我发现这里的很多答案都过于复杂或不准确(即实际上并没有去抖动)。这是一个带有检查的简单解决方案:

const [count, setCount] = useState(0); // simple check debounce is working
const handleChangeWithDebounce = _.debounce(async (e) => {
    if (e.target.value && e.target.value.length > 4) {
        // TODO: make API call here
        setCount(count + 1);
        console.log('the current count:', count)
    }
}, 1000);
<input onChange={handleChangeWithDebounce}></input>
于 2021-03-16T07:20:47.990 回答
1

一些答案忽略了如果您想使用事件对象(e)中的 e.target.value 之类的东西,当您通过 debounce 函数传递它时,原始事件值将为空。

看到这个错误信息:

警告:出于性能原因,此合成事件被重用。如果您看到这一点,则表示您正在访问已nativeEvent发布/无效合成事件的属性。这设置为空。如果您必须保留原始合成事件,请使用 event.persist()。

正如消息所说,您必须在事件函数中包含 e.persist() 。例如:

const onScroll={(e) => {
  debounceFn(e);
  e.persist();
}}

然后,当然,您的 debounceFn 需要在 return 语句之外限定范围,以便利用 React.useCallback(),这是必要的。我的 debounceFn 看起来像这样:

const debounceFn = React.useCallback(
  _.debounce((e) => 
      calculatePagination(e), 
      500, {
            trailing: true,
      }
  ),
  []
);

于 2021-09-07T21:10:40.637 回答
0

这对我有用:

handleChange(event) {
  event.persist();
  const handleChangeDebounce = _.debounce((e) => {
    if (e.target.value) {
      // do something
    } 
  }, 1000);
  handleChangeDebounce(event);
}
于 2021-01-12T09:57:42.630 回答
0

对于您的情况,它应该是:

search = _.debounce((e){
 let str = e.target.value;
 this.props.relay.setVariables({ query: str });
}, 500),
于 2020-05-17T22:42:57.093 回答
0
class MyComp extends Component {
  debounceSave;
  constructor(props) {
    super(props);
  }
  this.debounceSave = debounce(this.save.bind(this), 2000, { leading: false, trailing: true });
}

save()是要调用的函数

debounceSave()是您实际调用的函数(多次)。

于 2020-11-03T07:02:15.843 回答
0

这是正确的FC方法@

Aximili 只回答触发一次

import { SyntheticEvent } from "react"

export type WithOnChange<T = string> = {
    onChange: (value: T) => void
}

export type WithValue<T = string> = {
    value: T
}

//  WithValue & WithOnChange
export type VandC<A = string> = WithValue<A> & WithOnChange<A>

export const inputValue = (e: SyntheticEvent<HTMLElement & { value: string }>): string => (e.target as HTMLElement & { value: string }).value

const MyComponent: FC<VandC<string>> = ({ onChange, value }) => {
    const [reload, setReload] = useState(false)
    const [state, setstate] = useState(value)
    useEffect(() => {
        if (reload) {
            console.log('called api ')
            onChange(state)
            setReload(false)
        }
    }, [reload])

    const callApi = () => {

        setReload(true)
    } // You might be able to call API directly here, I haven't tried
    const [debouncedCallApi] = useState(() => _.debounce(callApi, 1000))

    function handleChange(x:string) {
        setstate(x)
        debouncedCallApi()
    }

    return (<>
        <input
            value={state} onChange={_.flow(inputValue, handleChange)} />
    </>)
}


于 2021-06-14T08:14:44.000 回答
-1

@Aximili

const [debouncedCallApi] = useState(() => _.debounce(callApi, 1000));

看起来很奇怪 :) 我提供解决方案useCallback

const [searchFor, setSearchFor] = useState('');

const changeSearchFor = debounce(setSearchFor, 1000);
const handleChange = useCallback(changeSearchFor, []);
于 2020-01-26T14:27:42.577 回答
-2
    const delayedHandleChange = debounce(eventData => someApiFunction(eventData), 500);

const handleChange = (e) => {
        let eventData = { id: e.id, target: e.target };
        delayedHandleChange(eventData);
    }
于 2021-05-13T18:00:41.167 回答