繁体   English   中英

React useCallback linting 错误缺少依赖项

[英]React useCallback linting error missing dependency

我在我的组件中使用自定义挂钩useInstantSearch

当我将它包装在useCallback中时,我收到以下错误:

React Hook useCallback received a function whose dependencies are unknown. Pass an inline function instead.

这是代码:

  const [searchTerm, setSearchTerm] = useState<string>(searchQuery);
  const handleDebouncedSearch = useCallback(
    useInstantSearch(searchTerm, (search, cancelTrigger, searchStillValid) => {
      console.log('instant search', search);
    }),
    []
  );

  useEffect((): void => {
    handleDebouncedSearch(searchTerm);
  }, [searchTerm, handleDebouncedSearch]);

如此有效地将更新的搜索词发送到子组件进行显示,然后父组件在该词更改时处理搜索的去抖动。

search, cancelTrigger, searchStillValid

不是父组件的一部分,它们是useInstantSearch的一部分。

这是我可以忽略的警告吗?

import { useEffect, useRef } from 'react';
import { CancelTrigger } from '../../../ars/api/api.cancel';

const DELAY_SEARCH_MS = 300;

interface InstantSearchOnChange {
  (search: string, cancelTrigger: CancelTrigger, resultStillValid: { (): boolean }): void;
}

/**
 * Helper to delay request until user stop typing (300ms), support deprecated requests (cancel and helper to not update the state), or unmounted component.
 */
export default function useInstantSearch(initialSearch: string, onChange: InstantSearchOnChange): { (value: string): void } {
    
  const search = useRef<string>(initialSearch);
  const requests = useRef<CancelTrigger[]>([]);

  const mounted = useRef<boolean>(true);

  useEffect(() => {
    return (): void => {
      mounted.current = false;
    };
  }, []);

  return value => {
    search.current = value;

    setTimeout(() => {
      if (search.current === value) {
        requests.current = requests.current.filter(r => !r.cancel());

        const trigger = new CancelTrigger();
        requests.current.push(trigger);

        onChange(value, trigger, () => search.current === value && mounted.current);
      }
    }, DELAY_SEARCH_MS);
  };
}

由于您使用的是一些外部 function,您可以简单地忽略该消息:

useCallback(
  useInstantSearch(...)
, []) // eslint-disable-line react-hooks/exhaustive-deps

但是,您应该像这样使用它:

  const [searchTerm, setSearchTerm] = useState<string>(searchQuery);
  const handleDebouncedSearch = useCallback(() => { // -> this
    useInstantSearch(searchTerm, (search, cancelTrigger, searchStillValid) => {
      console.log('instant search', search);
    })
  }, [searchTerm]); // eslint-disable-line react-hooks/exhaustive-deps

此处需要 Eslint 注释,因为您在 useInstantSearch 中使用回调,因为无法将它们作为依赖项注入。

如果您不介意陈旧的关闭,您可以忽略它,您可以这样做:

 const { useRef, useCallback, useEffect } = React; const DELAY_SEARCH_MS = 300; const later = (value, time) => new Promise((resolve) => setTimeout(() => resolve(value), time) ); /** * Helper to delay request until user stop typing (300ms), support deprecated requests (cancel and helper to not update the state), or unmounted component. */ function useInstantSearch(onChange) { const timeout = useRef(); const mounted = useRef(true); useEffect(() => { return () => { mounted.current = false; }; }, []); return useCallback( (value) => { clearTimeout(timeout.current); //cancel other timeout.current = setTimeout(() => { const current = timeout.current; onChange( value, () => //comparing timeout.current with current // async function may not be the last to resolve // this is important when you want to set state based // on an async result that is triggered on user input // user types "a" and then "b" if 2 async searches start // "a" and "ab" and "a" is so slow it will resolve after "ab" // then state result will be set for "ab" first and then with "a" // causing UI to be out of sync because user searched for "ab" // but results for "a" are shown timeout.current === current && mounted.current ); }, DELAY_SEARCH_MS); }, [onChange] ); } const App = () => { const handler1 = useCallback( (value) => console.log('handler1:', value), [] ); const handler2 = useCallback( (value) => console.log('handler2:', value), [] ); const handler3 = useCallback((value, shouldResolve) => { console.log('starting async with:', value); return later( value, value.length === 1? 1000: 800 ).then( (resolve) => shouldResolve() &&//you can opt not to set state here console.log('resolved with', resolve) ); }, []); const debounced1 = useInstantSearch(handler1); const debounced2 = useInstantSearch(handler2); const debounced3 = useInstantSearch(handler3); [1, 2, 3].forEach( (num) => setTimeout(() => { debounced1(num); debounced2(num * 2); }, 100) //lower than the 300 of debounce ); //both callbacks will be called but "a" resolves after "ab" since // "ab" was the last to be requested it will be the only one that logs // resolved with setTimeout(() => debounced3('a'), 500); setTimeout(() => debounced3('ab'), 1500); return 'hello world (check console)'; }; ReactDOM.render(<App />, document.getElementById('root'));
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <div id="root"></div>

您的问题可能有解决方案,但在不知道useInstantSearch是什么的情况下,不可能提供解决方案。

我的猜测是您应该在useInstantSearch useCallback由于您的问题中缺少该代码,因此我只能猜测。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM