4

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?

Bobby Tables
  • 163
  • 4
  • 17
  • Don't bother much on `react-hooks/exhaustive-deps`. It is only logical if you want to update the values when the dependencies change. Consider it as a suggestion and not a requirement. you might want to do something only once and have an empty `[]` as dependency. This would also throw a warning, though it is pointless – Dhananjai Pai Oct 31 '19 at 12:58
  • There are so many things happening in one effect. Probably it's best to separate them into multiple effects. – Joseph D. Oct 31 '19 at 13:48

1 Answers1

1

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?

Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • Cool thanks for the suggestion. Yeah I have seen some stuff where people said you shouldn't take the linter warnings too seriously, but I feel like you always should or they wouldn't be there. Glad to know the jury's out on this one though. Thanks! – Bobby Tables Oct 31 '19 at 13:05
  • the linter for this isn't perfect and it wouldn't know what you want and don't want. Linter here is to prompt you is you are missing anything by mistake and not to force it to add everything that is a dependency – Shubham Khatri Oct 31 '19 at 13:15