Stephan Bakkelund Valois
Stephan Bakkelund Valois

Reputation: 1072

React how to run a function only once, after page enter or refresh

I'm working on a search function with algolia search. The user may put in a search term from a different site, get redirected to the search page, and the search should be invoked.

After this, to search for more stuff, the user need to use the search bar in the search page, and hit enter to invoke the search again.

I've tried to use a useState and set it to true after the first render. However when I type in my search bar, the useEffect gets invoked at every key press. Why is this happening when firstRender doesn't change? It will set firstRender to true again, but since firstRender already is true, nothing should happen?

How can I "deactivate" the useEffect after the first render, so that the user only uses the search bar to search?

(I don't want to hammer the API with requests while the user is typing)

Thanks!

const SearchRecipes = () => {
  const client = algoliasearch(process.env.REACT_APP_ALGOLIA_APP_ID, process.env.REACT_APP_ALGOLIA_SEARCH_API);
  const index = client.initIndex('recipe_search');
  const match = useRouteMatch();
  const [searchTerm, setSearchTerm] = useState(match.params.id);
  const [searchReturnData, setSearchReturnData] = useState([]);
  const [firstRender, setFirstRender] = useState(false);
  const useMountEffect = (fun) => useEffect(fun, [])


  useEffect(() => {
    handleSubmit();
    setFirstRender(true);
  }, [firstRender])

  const handleSubmit = (e = null) => {
    if (e !== null){
      e.preventDefault();
    }

    index
      .search(searchTerm)
      .then((responses) => {
        setSearchReturnData(responses.hits);
      });
  }

  return (
    // irrelevant JSX
   <div className="keywords">
     <input 
       type="text" 
       value={searchTerm}
       onChange={({target}) => setSearchTerm(target.value)}
     />
   </div>
   // more irrelevant JSX
  )
} 

Upvotes: 6

Views: 11074

Answers (1)

Bruno Monteiro
Bruno Monteiro

Reputation: 4519

The reason is that your useEffect has a dependency on firstRender and inside it it is setting that value.

You could either follow the suggestion from the comment, using an empty array of dependencies:

useEffect(() => {
  handleSubmit();
}, [])

or check if your firstRender state is already set:

useEffect(() => {
  if (!firstRender) {
    handleSubmit();
    setFirstRender(true);
  }
}, [firstRender])

This is a really nice article about useEffect if you need more info.

Upvotes: 4

Related Questions