【问题标题】:Debounce not working as expected react context, api callDebounce 未按预期反应上下文,api 调用
【发布时间】:2021-06-17 00:53:14
【问题描述】:

使用 debounce 函数实现,没有 lodash 来自下面的要点

  1. utils.js
export const debounce = (fn, delay) => {
  let timer = null;
  return function (...args) {
      const context = this;
      timer && clearTimeout(timer);
      timer = setTimeout(() => {
          fn.apply(context, args);
      }, delay);
  };
}
  1. 标题
import React, { useEffect, useRef, useState, useContext } from 'react';
import SearchContext from "../Search/context"
import { debounce } from "../../utils";

function Header() {
const [searchBox, setSearchBox] = useState(false)
const ref = useRef(null)
const inputRef = useRef(null)
const { searchInput, updateSearchInput } = useContext(SearchContext)
...
render(
...
<input className="searchInput"
 ref={inputRef}
 value={searchInput}
 onChange={(e) => debounce(updateSearchInput(e.currentTarget.value), 2000)}
 onBlur={() => setSearchBox(false)}
 type="text" maxLength="80" />
...
)

}
export default Header;
  1. 搜索
import React, { useContext, useRef, useEffect, useState, useCallback } from "react"
import { debounce } from "../../utils";
import searchContext from "../Search/context"
import { apiCallMethod} from "../../api"

const Search = () => {
   const context = useContext(searchContext)
   const [results, setResults] = useState(null)

// context.searchInput is the value of the input box provided by SearchContext.Provider

const fetchData = useCallback(async () => {
   // the input string is the query param for the api request  
   return await apiCallMethod(context.searchInput, null).then(response => {
   setResults(response.results)            

   })

}, [context]);

useEffect(() => {

   debounce(fetchData(), 2000)

   return () => setResults(null)
}, [fetchData])

render(...)
}
export default Search

上面的组件发生了一些事情

由于我的应用程序相当大,我没有直接从 html input onChange 事件进行 API 调用。 我有一个反应上下文挂钩设置为searchContext,它存储在input 框中输入的文本值

通过上下文提供程序将相同的字符串提供给Search组件,它被称为context.searchInput

Search 中,有一个useEffect() 调用了返回渲染响应数据的Api 方法。

但是,debounce 没有按预期工作。它有时不会返回正确的结果,因为

  1. 结果集不代表最近输入的字符串,并且
  2. chrome devtools 显示它在 debounce 之前触发了对子字符串的过多请求

我尝试将debounce 包装在onChange 中,在Header 组件中,在Search 组件中,并同时包装两者。我也尝试将延迟从500 增加到2000,但没有帮助。

如果有副作用,我也可以删除 useCallback 挂钩。感谢反馈

参考文献

去抖实现 1 https://gist.github.com/simonw/c29de00c20fde731243cbac8568a3d7f

去抖实现 2 https://gist.github.com/sachinKumarGautam/6f6ce23fb70eec5d03e16b504b63ae2d

【问题讨论】:

标签: javascript reactjs async-await react-hooks


【解决方案1】:

我发现直接从 React 中使用 debounce 总是很棘手,并且会导致一些细微的错误。

我更喜欢使用useDebounce 钩子,它可以解决这个问题。这是解决方案的草稿:

const Search = () => {
   const context = useContext(searchContext)
   const [results, setResults] = useState(null)

   const input = context.searchInput;
   const dInput = useDebounce(input, 1000);

   const fetchData = useCallback(async () => {
     // the input string is the query param for the api request  
     return await apiCallMethod(dInput, null).then(response => {
       setResults(response.results)            

     })
   }, [dInput]);

  useEffect(() => {

     fetchData()

     return () => setResults(null)
  }, [dInput])
}

【讨论】:

  • 我进行了更改,它几乎可以完美运行,但是它发出了两个请求,一个请求第一个字母,另一个请求全文。例如,如果我输入“花园”,则两个请求是 search?q=gsearch?q=garden。我正在使用usehooks.com/useDebounce。调查
【解决方案2】:

代码应如下所示。因为您的 debounce 函数期望 fn & delay 作为参数,所以您需要传递函数 updateSearchInput 和 delay。如果你写updateSearchInput(e.currentTarget.value),你正在调用函数并且函数只在那里执行。此外,您的 debounce 正在返回另一个函数作为闭包(计时器),它期望 ...args 并传递给 fn.apply,因此它应该是 e.currentTarget.value

//add a new local state for the input
const [searchText, setSearchText] = useState('')

//set the new local state to input
<input className="searchInput"
 ref={inputRef}
 value={searchText}
 onChange={(e) => setSearchText(e.target.value)}
 onBlur={() => setSearchBox(false)}
 type="text" maxLength="80" />
...

//add an useEffect to trigger debounce
useEffect(() => {
 debounce(updateSearchInput, 2000)(searchText);

}, [searchText]);


【讨论】:

  • 我进行了更改,但现在input 框一次只呈现一个字母。例如,如果我键入“red”,则input 中只显示“d”,并且进行了三个 api 调用search?q=rsearch?q=esearch?q=dvalueonChange 绑定到反应上下文挂钩 const { searchInput, updateSearchInput } = useContext(SearchContext)
猜你喜欢
  • 2022-12-11
  • 2022-07-18
  • 1970-01-01
  • 1970-01-01
  • 2022-01-11
  • 2011-12-15
  • 1970-01-01
  • 2021-07-03
  • 2022-01-21
相关资源
最近更新 更多