簡體   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