-
클론코딩 트러블 슈팅(친구검색기능)카테고리 없음 2023. 5. 18. 13:47
POST요청으로 검색한친구를 response로 어떻게 바깥으로 빼와서 사용할 수 있는지가 첫 문제였다.
시도방법
1. onSuccess안에서 변수에 담아서 빼낸다.
- 지역변수기 때문에 밖에서 사용할 수 없다.
2. retrun문에 담아서 빼낸다.
const mutation = useMutation(detailSprint,{ onSuccess:(data)=>{ alert('검색요청 성공') return data }, onError:(error)=>{ console.log(error) } }) const userProfile = mutation.data.userInfos
data가 비동기 작업의 결과를 포함하는 개체여서 사용할 수없다고 에러가 난다.
3. retrun에 data.userInfos를 조회를 하면 아예 값이 담기지 않는 undefined가 나온다. 이유는 useMutation함수는 비동기작업을 수행하기 때문에 작업이 완료되기 전에 바로 결과를 반환하지 않는다. 따라서 함수가 완료되지 않은 상태에서 실행되므로 원하는 결과를 얻을 수 없다.
const mutation = useMutation(detailSprint,{ onSuccess:(data)=>{ alert('검색요청 성공') return data.userInfos }, onError:(error)=>{ console.log(error) } }) const userProfile = mutation console.log(userProfile)
4. 그래서 useEffect에 userProfile State를 만들어서 담은내용을 보여주게 할 수 있다.
const [userProfile, setUserProfile] = useState([]); const mutation = useMutation(detailSprint,{ onSuccess:(data)=>{ alert('검색요청 성공') setUserProfile(data.userInfos) }, onError:(error)=>{ console.log(error) } }) useEffect(()=>{ console.log(userProfile) },[userProfile])
useEffect(() => { // userProfile이 업데이트될 때마다 mutation.data.userInfos 값을 최신 값으로 업데이트 setUserProfile(mutation.data?.userInfos || []); }, [mutation.data]);
옵셔널 체이닝 연산자 (?.)를 사용해서 mutation.data값이 존재하면 그안에 userInfos가 존재할 경우에만 해당 값을 가져오게 처리했다. 그렇지 않을 경우 [] 빈배열을 userProfile에 할당했다.
이렇게 함으로써 mutation.data.userInfos값이 업데이트 될때마다 userProfile값이 최신 값으로 업데이트 되고 그 후에 userList컴포넌트에 suerProfile이 전달되게 할 수 있다.
이렇게 완료를 했지마 뇌피셜로 내가 원하는 키워드의 값을 가지고 오는거기때문에 get요청으로 처리할 수 는 없는가? 라는 의문이 들었다.
서버분과 소통으로 get요청으로 변경해서 다시 구현하기로 결정됬다.
처음 로직을 짤때 useQuery를 이용해서 데이터를 불러왔느데
const { isLoading, isError, data } = useQuery("userSearch", () => userSearch(name) );
이렇게 조회를 하면 화면이 렌더링 되면 검색을 안해도 조회가 되버려서 데이터를 받지 못하고 계속 요청을 하게됬다.
useQuery훅은 컴포넌트가 마운트될 때 자동으로 요청을 보내는 특성이 있다. 따라서, 초기 렌더링시에도 요청이 발생할 수 있다.
이를 방지하기 위해 useQuery훅에 enabled 옵션을 사용하여 요청을 제어할 수 있다.
enabled 옵션은 useQuery훅이 활성화되는지 여부를 결정하는 불리언 값이다. 기본적으로 true로 설정되어 있어서 컴포넌트가 렌더링 될때 요청이 자동으로 발생한다. 하지만 enabled값을 false로 설정하면 초기 렌더링 시에는 요청이 발생하지 않는다.
따라서 검색버튼을 클릭하여 검색을 실행하고자 할 때에만 요청을 보내도록 할 수 있다.
const [name, onChangeSearchNameHandler] = useInput(''); const [searchEnabled, setSearchEnabled] = useState(false); const { isLoading, isError, data } = useQuery("userSearch", () => userSearch(name), { enabled: searchEnabled } // enabled 옵션 추가 ); const handleSubmit = (e) => { e.preventDefault(); setSearchEnabled(true); // 검색 버튼 클릭 시 요청 활성화 };
이렇게 하면 잘 불러와지긴 하나 처음 렌더링 되었을때 검색어가 없어서 이런 에러가 뜬다.
{searchEnabled && data ? ( <UserItem users={data} /> ) : ( <p>검색 결과가 없습니다.</p> )}
조건식을 줘서
searchEnabled가 true이면서 data의 값이 있을때 UserItem컴포넌트가 실행이 되고 아니라면 검색결과가 없다는 메세지가 보여지게 했다.
이렇게하면 정상적으로 불러와지고 보여지게 할 수 있는데 또다른 문제가 생긴다.
키워드를 검색 후 새로고침 안하고 다시 데이터를 불러오려 했을때 그 동작이 너무 오래걸린다.
const userSearch = async (props) => { console.log(`props:`, props) try { const response = await instance.get(`/api/user/${props}`) return response.data; } catch (error) { throw new Error(error.message); } };
API요청 로직인데 데이터가 여기에 넘어와서 콘솔에 찍히는게 오래걸리는걸 볼 수 있었다.
결과적으로 서버에서 데이터를 늦게 내려주는게 아니고 클라이언트단에서 문제라는걸 알 수 있다.
문제는 두번째 검색 요청은 캐시된 데이터를 사용하려해서 늦어지게된다고 한다.
기본적으로 캐시된 데이터를 사용하여 요청을 만족시키려고 하지만, 데이터를 새로고침이 필요하다.
방법 : 캐시를 무효화하기
useMutation훅을 사용하여 검색 요청을 보낼 때 해당 요청에 대한 응답을 받으면 캐시된 데이터를 무효화 할 수 있다. useMutation훅은 onSuccess콜백을 제공하는데 이 콜백에서 queryClient.invalidateQueries("useRSerch")를 호출하여 해당 쿼리의 캐시를 무효화 할 수 있다.
이렇게 되면 onSuccess에서 state값에 담아서 뺀걸 어떻게 조건문을 사용해서 보여주냐의 문제가 또 발생한다.
{searchUsers.length > 0 ? ( <UserItem users={searchUsers} /> ) : ( searchEnabled && <p>검색 결과가 없습니다.</p> )}
위 코드에서 searchUsers 상태 변수를 사용하여 검색이 활성화되었는지 확인된다. 검색 버튼을 클릭하여 API요청 시작되면 searchEnabled값을 true로 설정하고 api요청전에는 searchEnabled값이 false이므로 검색결과가 없다는 메세지가 안나오게 한다.
시도1.
{searchEnabled && searchUsers.length>0? ( <UserItem users={searchUsers} /> ) : ( <p>검색 결과가 없습니다.</p> )}
시도2.
{searchEnabled && searchUsers.length>0? ( <UserItem users={searchUsers} /> ) : ( <p>검색 결과가 없습니다.</p> )}
해결방법 :
const mutation = useMutation((name)=> userSearch(name),{ onSuccess:(data)=>{ setSearchUsers(data.userInfos) setSearchEnabled(true) } }) {searchEnabled && searchUsers.length > 0 ? ( <UserItem users={searchUsers} /> ) : ( searchEnabled && <p>검색 결과가 없습니다.</p> )}
문제는 setSearchUsers로 넣어줄때 userInfos까지 안넣어주면 배열이 아니게되어서 searchUsers.length > 0 이 조건문이 실행되지 않아 보이지 않았다.
결론 : useQuery는 데이터를 가지고와서 캐시에 저장하는 특성을 가지고있어서 장점으로는 중복을 피할 수 있지만 다른키워드로 검색하려하면 이전 캐시내역때문에 빠르게 재 요청 하지 못한다. 하므로 useMutation을 사용해서 중복된 내역이더라도 캐시를 무효화할 수 있다.