개발자

안녕하세요.. 정말 이것저것 다 해봤는데 안되네요 ㅠ

2024년 06월 25일조회 119

안녕하세요. 리액트와 리액트 쿼리를 이용해 프로젝트를 진행 중 입니다. 저는 일단. src/hooks/useProduct.jsx 라는 커스텀 훅 을 만들었습니다. 제 계획은 1. 맨 처음 최상단 Home.jsx 에서 useProduct 라는 커스텀 훅 호출 2. 자식컴포넌트에 data를 전달 3. Search.jsx에서 받은 filter값으로 커스텀 훅 안의 query 재실행 4. 바뀐 상태는 Home.jsx 가 다시 받고 자식 컴포넌트에게 전달. 1~3까지는 콘솔찍어가면서 잘 되는데 4.는 되지 않습니다. (쿼리 데이터가 바뀌어도 4이 재 실행이 안됨..) ㅠㅠㅠㅠㅠㅠㅠ 쿼리 옵션도 줘보고 전역 상태도 만들어보고 이것저것 다 해봤는데 ㅠㅠ 혹시 아시는분 계신가요..? 어떠한 답변도 정말 감사히 받겠습니다 간략 코드첨부) Home.jsx const Home = ()=>{ const { data, error, isLoading } = useProduct(); return ( <Search /> <List data={data?.product} /> ); }; export default Home; Search.jsx const Search = () => { ```일부코드생략``` const { updateQuery } = useProduct (); const handleSubmit = () => { const searchData = { productId }; updateQuery(productId); }; } return( ```일부코드생략``` <button onClick={handleSubmit}> 조회 </button> ) } export default Search; useProduct.jsx const useProduct = () => { const [queryData, setQueryData] = useState(); const { data, error, isLoading } = useQuery({ queryKey: ["product", queryData], queryFn: () => fetchProduct(queryData), }); const updateFilters = (queryData) => { setQueryData(() => (queryData); }; return { data, error, isLoading, updateQuery , }; export default useProduct ;

이 질문이 도움이 되었나요?
'추천해요' 버튼을 누르면 좋은 질문이 더 많은 사람에게 노출될 수 있어요. '보충이 필요해요' 버튼을 누르면 질문자에게 질문 내용 보충을 요청하는 알림이 가요.
profile picture
익명님의 질문

답변 3

포크코딩님의 프로필 사진

리액트 쿼리를 사용할 때 쿼리를 수동으로 다시 진행하려면 refetch 함수를 사용하셔야 합니다. useQuery 훅에서 리턴하는 객체에서 구조할당 받아 사용할 수 있습니다.

profile picture

익명

작성자

2024년 06월 26일

리턴하는 컴포넌트가 다시 재 랜더링이 안돼서 (콘솔찍어보면 아무것도 안나옴) 리턴하는 객체에서 refetch를 사용할 수 없습니다 ㅠㅠ 답변 너무 감사합니다!

포크코딩님의 프로필 사진

포크코딩

별빛상단 단주2024년 06월 26일

음...뭔가 내가 이거 때문에 삽질을 했다고? 정도로 간단한거에서 놓치고 있으신듯 한데.. 이런게 은근 찾기 어렵긴 하거든요. 코드를 직접 볼 수 있으면 바로 해결 할텐데 잘 모르겠네요.

삭제된 사용자님의 프로필 사진

삭제된 사용자

2024년 06월 26일

useProduct를 2번 사용하여 updateQuery를 Search 컴포넌트에서 사용하셨네요. Home 컴포넌트에서 사용하셔야 합니다. updateQuery를 prop으로 내려줘서 동작해보셔요.

1// Home
2<Search updateQuery={updateQuery} />
3<List data={data?.product} />
4
5
6// Search
7const Search = ({ updateQuery }) => {
8const handleSubmit = () => {
9          ...
10          updateQuery(productId);
11       };
12
13}
profile picture

익명

작성자

2024년 06월 26일

답변 정말 감사합니다! 선생님이 써주신 코드 잘 동작합니다. 그런데 제가 하고 싶은 건 props 를 다 없애고 사용컴포넌트 에서 useProduct 를 사용해 모든 처리를 하고 싶은데 그건 불가능 할까요..? Home.jsx <Search/> <List/> 이런식으로 만들고 싶습니다.

profile picture

익명

작성자

2024년 06월 26일

React-Query는 queryKey를 통해 데이터를 캐싱하기 때문에 원하시는대로 동작할려면 queryKey를 동일하게 맞춰줘야 해요. 지금은 Home에서 호출한 useProduct의 queryKey와 Search에서 호출한 useProduct의 queryKey가 동일하지 않아요. 각각 useState를 호출하기 때문에 Home에서는 ["product", queryData], Search에서의 ["product", queryData]가 다르게 작동합니다. queryData를 콘솔로 찍어보시면 좀 더 이해가 가실거에요. 전역변수를 사용하든, url parameter에서 keyword를 추출하든 (ex : search?searchKeyword=something) useQuery의 ["product", queryData]를 동일하게 맞춰주세요.

삭제된 사용자님의 프로필 사진

삭제된 사용자

2024년 06월 26일

example

1const {
2    query: { searchKeyword },
3  } = useRouter();
4
5  const { data, error, isLoading } = useQuery({
6    queryKey: ["product", searchKeyword],
7    queryFn: () => fetchProduct(keyword),
8  });
profile picture

익명

작성자

2024년 06월 27일

와ㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏ "각각" useState를 호출하기 때문에 Home에서는 ["product", queryData], Search에서의 ["product", queryData]가 다르게 작동합니다. 이 중요한걸 놓치고 있었네요ㅋㅋㅋㅋㅋㅋㅋㅋㅋ queryData를 Context API 를 사용하여 해결하였습니다(❁´◡`❁) 와 이걸 어떻게 감사의 표현을 전해야할지... 선생님 감사합니다. 오늘 정말 큰 깨달음을 얻고 갑니다.

profile picture

익명

작성자

2024년 06월 27일

해결하셔서 다행이에요 :)

지금 가입하면 모든 질문의 답변을 볼 수 있어요!

현직자들의 명쾌한 답변을 얻을 수 있어요.

또는

이미 회원이신가요?

AI 답변
커리어리 AI 봇 프로필 이미지

커리어리 AI 봇

GPT가 달아주는 답변입니다.

2024년 06월 25일

리액트 쿼리의 `useQuery`는 의존성 배열이 변경될 때 쿼리를 다시 실행합니다. 이 경우, 제공된 query key가 변경될 때마다 리액트 쿼리가 데이터를 다시 불러온다는 원칙을 이용하면 해결할 수 있습니다. 문제는 `useProduct` 훅에서 `queryData` 상태 변경이 일어나더라도, Home 컴포넌트에서 리렌더링이 발생하지 않아서 update가 안 되고 있는 것으로 보입니다. 대부분의 경우, 같은 custom hook을 여러 컴포넌트에서 사용하게 되면 각각의 컴포넌트는 독립적인 상태를 갖게 됩니다. 그래서 Search 컴포넌트에서 `updateQuery`를 호출하여 상태를 업데이트해도 Home 컴포넌트의 상태에는 영향을 주지 못하는 것입니다. 이 문제를 해결하기 위해서는 context API 또는 state management library(redux, mobx 등)을 사용하는 방법이 있습니다. 상위 컴포넌트에서 상태를 관리하고, 하위 컴포넌트로 props로 넘겨주거나 Context API, Redux 등을 사용하여 전역 상태 관리를 하는 방식으로 해야 합니다. 아래와 같이 코드를 수정해보세요. ```javascript // Create context for product import React, { useState, createContext } from 'react'; export const ProductContext = createContext(); export const ProductProvider = ({ children }) => { const [productId, setProductId] = useState(null); return ( <ProductContext.Provider value={{ productId, setProductId }}> {children} </ProductContext.Provider> ) } // Modify Home.jsx import { useContext } from "react"; import { ProductContext } from "./context/ProductContext"; const Home = () => { const { productId } = useContext(ProductContext); const { data, error, isLoading } = useProduct(productId); return ( <div> <Search /> <List data={data?.product} /> </div> ); }; // Modify Search.jsx import { useContext } from "react"; import { ProductContext } from "./context/ProductContext"; const Search = () => { ... const { setProductId } = useContext(ProductContext); const handleSubmit = () => { ... // update the productId in global context setProductId(productId); } return( ... ); } // Modify useProduct.jsx const useProduct = (productId) => { ... const { data, error, isLoading } = useQuery(["product", queryData], () => fetchProduct(queryData) ); return { data, error, isLoading, } } ``` 이렇게 하면 원하는 동작을 수행할 수 있습니다.

목록으로

지금 가입하면 모든 질문의 답변을 볼 수 있어요!