아 그거 뭐였지

[React] useQuery 버튼 누를때만 실행 본문

Front-End

[React] useQuery 버튼 누를때만 실행

승발자 2022. 10. 23. 19:53
728x90
반응형

삽질의 과정

(결론부터 보기)


if문에 useQeury 넣어버리기

단순하게 페이지에서 GET 요청을 할때는 useQuery를 사용해서 GET요청을 하는 함수를 부르기만 하면 됐었다.

이번에는 검색 버튼을 눌렀을때만 GET요청을 하고싶어서 Enter버튼이 눌렸을때만 useQuery를 사용하면 되지 않을까 싶어서 다음과 같이 코드 작성을했었다.

const productName = useRef('');
 
const handleKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === 'Enter' && productName.current.length>0) {
    	//Enter버튼을 눌렀을때에만 작동
        //useQuery 커스텀훅
        useSearchProducts(productName.current)
    }
};

그럼 바로 에러를 뱉어버리는데 리액트 hook 이름은 use로 시작해야된다라는 에러가 나온다.

React Hook "useSearchProducts" is called in function "handleKeyPress" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use" eslint (react-hooks/rules-of-hooks)

handleKeyPress에 use이름을 안붙여서 그런가? 싶어서 함수이름을 바꿔보기도 하고 대문자로 바꿔보기도 했지만

근본적인 오류의 원인은 그것이 아니였다.

 

에러의 원인은 if 문 안에서 use hook을 사용했기때문이다.

에러에서 eslint (react-hooks/rules-of-hooks) 이부분이 해당 공식문서 페이지로 연결할수있는 링크여서 클릭해보니

 

useQuery뿐만 아니라 리액트 hook은

루프문이나 조건문에서는 수행하면 안되며,  최상위 레벨에서만 호출해야 한다고한다.

 

Only Call Hooks at the Top Level

Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multiple and calls. (If you’re curious, we’ll explain this in depth below.)useStateuseEffect

 

기본도 잘 숙지하지 못한채 if문에 useQuery를 넣고서 왜 안되는지 고민하고있었던 것이였다.

문제의 원인은 알았지만 해결책은 찾지못하고있었다. useQuery를 버튼을 누를때만 호출하고 싶은데

최상위 레벨에서 호출해버리면 버튼 누르기전에 호출이 되는게 아닌가? if문에 넣을수가 없었기 때문이다.

검색을 해보니 useQuery의 refeth함수와 enabled옵션을 사용하면 버튼을 누를때만 호출할수있겠다 싶었다.

 

  • refetch: 쿼리를 수동으로 다시 가져오는 함수이다.
  • enabled: false값을주면 해당 쿼리가 자동으로 실행되지 않는다.

 

따라서 코드를 다음과 같이 수정하니 작동하였다.

 

해결

products.tsx
//useSeartchPorudtcs는 enabled 옵션이 false이므로 refetch를 호출하기 전까지는 호출이되지않는다.
const { data,refetch } = useSearchProducts(productName.current);

const handleKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => {
	if (e.key === 'Enter' && productName.current.length>0) {
    		refetch();
	}
};
useSearchProducts.ts
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { searchProducts } from "../api/searchProudct";

/** 검색상품 가져오기 */
export const useSearchProducts = (productName:string) => {
  const queryClient = useQueryClient();
  return useQuery(["search",productName], () => searchProducts(productName),
  {
    // 수동적으로 호출할때만 호출되게 하는 옵션 (refetch를 사용하는 이유)
    enabled:false,
  }
  );
};

 

+ 해결에 도움을 주신 스택오버플로우 형님과 리액트 공식문서에게 감사...

https://stackoverflow.com/questions/62340697/react-query-how-to-usequery-when-button-is-clicked

 

React-Query: How to useQuery when button is clicked

I am new to this react-query library. I know that when I want to fetch data, with this library I can do something like this: const fetchData = async()=>{...} // it starts fetching data from

stackoverflow.com

https://reactjs.org/docs/hooks-rules.html

 

Rules of Hooks – React

A JavaScript library for building user interfaces

reactjs.org

 

728x90
반응형
Comments