[英]React useCallback linting error missing dependency
I am using a custom hook useInstantSearch
in my component.我在我的组件中使用自定义挂钩
useInstantSearch
。
When I wrap it in useCallback
to I get the following error:当我将它包装在
useCallback
中时,我收到以下错误:
React Hook useCallback received a function whose dependencies are unknown. Pass an inline function instead.
This is the code:这是代码:
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]);
So effectively to send the updated search term to a child component for display only then the parent handles the debouncing of the search when that term changes.如此有效地将更新的搜索词发送到子组件进行显示,然后父组件在该词更改时处理搜索的去抖动。
search, cancelTrigger, searchStillValid
Are not part of the parent component, they are part of useInstantSearch
.不是父组件的一部分,它们是
useInstantSearch
的一部分。
Is this a warning I can ignore?这是我可以忽略的警告吗?
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);
};
}
Since you're using some external function, you can simply ignore the message:由于您使用的是一些外部 function,您可以简单地忽略该消息:
useCallback(
useInstantSearch(...)
, []) // eslint-disable-line react-hooks/exhaustive-deps
However, you should be using it like:但是,您应该像这样使用它:
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 comment is required here because, you're using callback inside useInstantSearch as there's no way to inject them as dependency.此处需要 Eslint 注释,因为您在 useInstantSearch 中使用回调,因为无法将它们作为依赖项注入。
You can ignore it if you don't mind the stale closures you can do it that way:如果您不介意陈旧的关闭,您可以忽略它,您可以这样做:
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>
There may be a solution to your problem but without knowing what useInstantSearch
is it's impossible to provide one.您的问题可能有解决方案,但在不知道
useInstantSearch
是什么的情况下,不可能提供解决方案。
My guess is that you should use useCallback
inside useInstantSearch
but since that code is missing from your question I can only guess.我的猜测是您应该在
useInstantSearch
useCallback
由于您的问题中缺少该代码,因此我只能猜测。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.