【问题标题】:Lodash debounce with React InputLodash 使用 React 输入去抖动
【发布时间】:2016-07-17 14:08:11
【问题描述】:

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

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

【问题讨论】:

标签: reactjs lodash relay debouncing


【解决方案1】:

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

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

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

如果您使用的是 es2015+,您可以直接在 constructorcomponentWillMount 之类的生命周期方法中定义您的 debounce 方法。

示例:

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)
}

【讨论】:

  • 谢谢。我现在看到的是合成事件的控制台日志,我需要 e.target.value 来执行搜索。我试过 e.persist() 但它似乎没有做任何事情。去抖动在技术上是有效的,但如果没有传递一个值,它就不起作用。感谢您的帮助。
  • 我不能完全使用它,但它让我到达了我需要去的地方。我基本上有输入调用 search(e) 然后将该事件传递给另一个具有去抖动功能的函数。我读到了 event.persist() 但我无法完成这项工作。谢谢你的帮助!!
  • @Jeff Wooden fidden 坏了
  • 感谢您推荐 componentWillMount。能够在 debounced 函数中访问 props 函数。如果我放入构造函数,不知何故我无法访问道具功能。
  • @RajeshMbm 您可以在类构造函数中访问道具,请参阅更新后的示例 - 它可作为第一个参数使用(确保包含 super 调用)。
【解决方案2】:

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

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} />
  </>);
}

【讨论】:

  • useEffect 仅触发一次,因为第一次调用后重新加载将始终为真。
  • 尝试将你的值设置为handleChange,而不是debouncedCallApi,然后callApi -> state,在这个useEffect触发你的函数之后^_^
【解决方案3】:

使用功能性反应组件尝试使用useCallbackuseCallback 记住你的去抖动函数,所以当组件重新渲染时它不会一次又一次地重新创建。如果没有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} />
}

`

【讨论】:

  • 你在导入中有错字: import _debouce from 'lodash/debounce';这不是 _debouce 它是 _debounce
  • 谢谢你!
  • 只是一个警告,useCallback 会将所有带有useState 的变量设置为加载页面的初始值。我遇到了这个错误,现在正试图找到另一种使用去抖动器的方法。
  • @FiddleFreak 我从未经历过。我认为问题是别的。
  • @JulesPatry 实际上我通过这样做解决了这个问题 > stackoverflow.com/questions/70501416/…
【解决方案4】:

这不是那么容易的问题

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

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

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

【讨论】:

    【解决方案5】:

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

    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>
    

    【讨论】:

      【解决方案6】:

      对于您的情况,应该是:

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

      【讨论】:

        【解决方案7】:
        class MyComp extends Component {
          debounceSave;
          constructor(props) {
            super(props);
          }
          this.debounceSave = debounce(this.save.bind(this), 2000, { leading: false, trailing: true });
        }
        

        save()是要调用的函数

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

        【讨论】:

          【解决方案8】:

          这对我有用:

          handleChange(event) {
            event.persist();
            const handleChangeDebounce = _.debounce((e) => {
              if (e.target.value) {
                // do something
              } 
            }, 1000);
            handleChangeDebounce(event);
          }
          

          【讨论】:

          • 我认为它调用了 n 次,并且只是应用了这样的延迟,次,我至少现在尝试过。
          【解决方案9】:

          这是正确的 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)} />
              </>)
          }
          
          
          

          【讨论】:

            【解决方案10】:

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

            查看此错误消息:

            警告:出于性能原因,此合成事件会被重复使用。如果您看到此内容,则表示您正在访问已发布/无效合成事件上的属性 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,
                  }
              ),
              []
            );

            【讨论】:

            • 我会避免将useCallback 与去抖器一起使用。这将强制所有 useState 挂钩从页面加载时重置为初始状态。
            【解决方案11】:

            @Aximili

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

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

            const [searchFor, setSearchFor] = useState('');
            
            const changeSearchFor = debounce(setSearchFor, 1000);
            const handleChange = useCallback(changeSearchFor, []);
            

            【讨论】:

              【解决方案12】:
                  const delayedHandleChange = debounce(eventData => someApiFunction(eventData), 500);
              
              const handleChange = (e) => {
                      let eventData = { id: e.id, target: e.target };
                      delayedHandleChange(eventData);
                  }
              

              【讨论】:

              • 最好解释一下你的答案,它在做什么,它是如何解决OP的问题的,根据需要提供一些参考。仅添加代码块或链接是不够的。 Check StackOverflow answer guide
              猜你喜欢
              • 2017-05-03
              • 2019-01-21
              • 2017-09-28
              • 2020-06-24
              • 2021-07-16
              • 2015-05-21
              • 2013-03-10
              • 2017-07-08
              • 1970-01-01
              相关资源
              最近更新 更多