Bobby Tables
Bobby Tables

Reputation: 163

Adding dependency in useEffect hook causes infinite loop

I have a wrapper component around a search bar that fetches suggestions with each keystroke and then searches either when a suggestion is chosen or the user hits enter/search. Upon choosing a search value, I want to persist that search item to local storage, so that I can show it on focus, much like Google. Here is a snippet of my component

export default function App() {
    const [results, resultsLoading, resultsError, setParams] = useFetch();
    const [suggestions, ,suggestionsError, setSuggestionsParams] = useFetch();
    const [showSearchSuggestions, setShowSearchSuggestions] = useState<boolean>(true);
    const [recentSearches, setRecentSearches] = useLocalStorage('recent_searches', []);
    const [searchAttributes, setSearchAttributes] = useState<SearchAtrributesInterface>({
        value: '',
        fetchType: SEARCH_FETCH_TYPES.SUGGESTIONS
    });

    useEffect(() => {
        const getSearchSuggestions = () => setSuggestionsParams(getAutoCompleteURL(searchAttributes.value));
        const getSearchResults = () => {
            setParams(getSearchURL(searchAttributes.value));
            setShowSearchSuggestions(false);
        };

        if (searchAttributes.value) {
            if (searchAttributes.fetchType === SEARCH_FETCH_TYPES.SUGGESTIONS) {
                getSearchSuggestions();
            } else {
                getSearchResults();
                setRecentSearches([searchAttributes.value, ...recentSearches])
            }
        }
    }, [searchAttributes, setParams, setSuggestionsParams]);

    return ( ... );
};

This works fine, but then I get hit with the linting warning: React Hook useEffect has missing dependencies: 'recentSearches' and 'setRecentSearches'. Either include them or remove the dependency array react-hooks/exhaustive-deps. Upon adding those two into the dependency array, I get stuck in an infinite loop because of course recentSearches's state is getting set, causing it to re-render and so on. I'd like to find a solution as oppose to adding // eslint-disable-next-line because I feel there is something truly wrong that I am doing. Does anyone know what I could do differently to prevent the infinite loop and prevent the linter warning?

Upvotes: 4

Views: 1372

Answers (1)

Shubham Khatri
Shubham Khatri

Reputation: 281636

There ware two things to it.

Since you wish to make use of the existing state value to update the same state you should use callback approach

setRecentSearches(prevRececentSearches => ([searchAttributes.value, ...prevRececentSearches]));

Also when you are absolutely sure that you haven't missed any dependency, you can disable the warning. Please check this post for more details: How to fix missing dependency warning when using useEffect React Hook?

Upvotes: 1

Related Questions