React-query 데이터 업데이트 (Chat gpt)

이서우·2023년 4월 29일
0

문제 발생

Explore 페이지에서 top Latest People로 이동할때 데이터가 제대로 업데이트가 안된채 prop로 넘겨지는 문제가 발생.

데이터가 넘겨지는 과정

Explore 페이지에서 react-query로 데이터를 받음
=> 성공하면 응답값을 set함수로 exploreData라는 state에 담기
=> tweetBox컴토넌트에 prop으로 exploreData 넘겨줌

여기서 다른 종류의 데이터를 받아와야하는 페이지로 이동하면 과거의 데이터만 보내지고 새로운 데이터로 업데이트가 안됨.

Chat gpt

Q.안녕 지금 react-query로 데이터를 업데이트 시켜서 다른 컴포넌트에 prop으로 보내주고 있는데 제대로 업데이트가 안된채 prop으로 넘겨지는 문제가 발생하고 있어.
다음은 나의 코드인데 여기서 문제점과 해결코드를 제시해줘

🔴 두가지 방법을 제시해줌. react-query에서 자동적으로 업데이트 시켜주는 data를 prop으로 바로 보내주거나
🔴 useCallback으로 exploreData 상태를 업데이트하는 함수를 만든다음, useEffect을 사용해서 데이터가 변경될때마다 set함수 실행시켜주기

안녕하세요! 코드를 확인해보니, useQuery hook을 사용하여 데이터를 가져오고, onSuccess 콜백 함수를 통해 setExploreData 함수를 사용하여 exploreData 상태를 업데이트하고 있습니다. 그러나 exploreData가 prop으로 전달될 때 업데이트가 제대로 이루어지지 않는 문제가 있습니다.

이 문제를 해결하기 위해서는 exploreData 상태를 업데이트하는 것 외에도, exploreData가 사용되는 컴포넌트에서도 해당 상태를 업데이트해주어야 합니다.

Q.위의 문제점에서 exploreData상태를 업데이트 하는것외에도 그 데이터가 사용되는 컴포넌트에서도 업데이트해야 되는 이유가 뭐야? react-query에서 set함수를 사용하면 exploreData가 업데이트 되는것과는 상관없는거야?

exploreData 상태가 업데이트되면 해당 데이터를 사용하는 컴포넌트에서는 다시 렌더링이 발생합니다. 이는 React의 원리로, 컴포넌트는 그것이 의존하는 상태가 변경될 때마다 다시 렌더링됩니다.

따라서, exploreData 상태가 업데이트되면, 해당 데이터를 사용하는 모든 컴포넌트에서도 새로운 데이터로 업데이트가 이루어지며, 렌더링이 발생합니다.

react-query에서 set 함수를 사용하면 exploreData가 업데이트되어도 해당 데이터를 사용하는 컴포넌트가 자동으로 업데이트되지는 않습니다.

그러면 react-query에서 set함수를 사용해서 exploreData가 업데이트될때 해당 데이터를 사용하는 컴포넌트가 자동적으로 업데이트 되게할려면 어떻게 해야해?

react-query에서 데이터를 가져올 때, 해당 데이터가 변경되면 useQuery 훅에서 반환하는 데이터 객체의 data 속성 값이 자동으로 업데이트됩니다. 이렇게 업데이트된 data 값을 사용하는 컴포넌트는 자동으로 리렌더링되어 변경된 데이터가 반영됩니다.

하지만, 직접 set 함수를 사용하여 exploreData 값을 업데이트하면 useQuery 훅에서 반환하는 데이터 객체의 data 값은 변경되지 않습니다. 따라서, 해당 데이터를 사용하는 컴포넌트가 자동으로 업데이트되지 않습니다.

이 문제를 해결하기 위해서는 set 함수를 사용하는 대신, mutate 함수를 사용하여 exploreData 값을 업데이트해야 합니다. mutate 함수는 서버에 데이터를 업데이트하는 역할을 하면서, 업데이트된 데이터를 자동으로 다시 가져오고 캐시에 저장합니다. 이를 통해, useQuery 훅에서 반환하는 데이터 객체의 data 값이 업데이트되어 해당 데이터를 사용하는 컴포넌트가 자동으로 업데이트됩니다.

🔴 react-query에서 onSuccess 콜백함수로 exploreData가 자동적으로 업데이트 되는데 왜 tweetBox에 prop으로 넘겨줄때는 exploreData가 업데이트가 되지 않은채 넘어가는지 아직도 이해가 안되어서 다시 찾아봄

> 그렇다면 여기서는 왜 tweetBox에 prop으로 넘겨준 exploreData가 업데이트 되지않은채 넘거가는거야?(코드도 함께)

tweetBox에 넘겨준 exploreData prop은 초기 렌더링 시에만 해당 값이 할당됩니다. 이후 exploreData 값이 업데이트 되어도, tweetBox 컴포넌트는 이를 감지하지 않으므로 업데이트된 값을 받아오지 못합니다.

따라서, tweetBox 컴포넌트에도 업데이트된 exploreData 값을 전달하기 위해서는 props를 업데이트해주는 방식으로 해결해야 합니다. 이를 위해 tweetBox 컴포넌트 내부에서 useState와 useEffect를 이용하여, exploreData 값을 저장하고 변경사항이 생길 때마다 업데이트하는 로직을 추가해야 합니다.

> "tweetBox에 넘겨준 exploreData prop은 초기 렌더링 시에만 해당 값이 할당됩니다. 이후 exploreData 값이 업데이트 되어도, tweetBox 컴포넌트는 이를 감지하지 않으므로 업데이트된 값을 받아오지 못합니다."
왜 이렇게 되는지 자세히 설명해줘

React에서 부모 컴포넌트에서 자식 컴포넌트로 props를 전달할 때, props가 전달되는 것은 값(value)이 전달되는 것이 아니라, props의 reference가 전달됩니다. 이 말은 즉, props가 변경되면 해당 값이 전달된 자식 컴포넌트에서 props를 다시 받아와도, props의 reference가 같기 때문에 이전에 받아온 값과 동일한 값을 받아오게 된다는 것입니다.

따라서, tweetBox 컴포넌트에 전달된 exploreData prop은 초기 렌더링 시에 해당 값의 reference가 전달되어 해당 컴포넌트 내부에서 사용됩니다. 그 이후, exploreData 값이 변경되어도, 해당 값을 받아와서 다시 렌더링하는 것이 아니라, 변경된 값의 reference가 생성되어 해당 컴포넌트 내부에서 사용되는 것이 아니기 때문에 변경된 값을 감지할 수 없게 됩니다.

따라서, exploreData 값이 변경되었을 때 tweetBox 컴포넌트에서도 새로운 값을 사용할 수 있도록, 부모 컴포넌트에서 exploreData 값을 변경하면서 해당 값을 tweetBox 컴포넌트로 다시 전달해 주어야 합니다. 이를 해결하기 위해서는 부모 컴포넌트에서 exploreData 값이 변경될 때마다 tweetBox 컴포넌트에게 새로운 값이 전달되도록 코드를 수정해야 합니다.

이를 위해서는 tweetBox 컴포넌트에서 exploreData props가 업데이트될 때마다 다시 렌더링될 수 있도록, useEffect를 사용하여 exploreData 값이 변경될 때마다 tweetBox 컴포넌트를 다시 렌더링하도록 코드를 수정해야 합니다. 예를 들어, 다음과 같이 코드를 수정할 수 있습니다.

function TweetBox(props: any) {
  useEffect(() => {
    console.log(props.data);
  }, [props.data]); // props.data 값이 변경될 때마다 useEffect가 실행됩니다.

  return (
    <div>
      {/* tweet 데이터를 렌더링하는 코드 */}
    </div>
  );
}

이제 exploreData 값이 변경될 때마다 tweetBox 컴포넌트에서 해당 값을 감지하고 적절히 렌더링할 수 있게 됩니다.

계속 useEffect를 사용하는 것보다 변경된 data를 바로 보내고 싶어서

> 그렇다면 exploreData 초기 reference의 값을 변경해주는 방법은 없는거야?
이렇게 react-query의 data를 바로 보내주니까 데이터가 제대로 업데이트되는데 그거는 props의 reference와는 관계없는거야?

맞습니다. react-query에서 반환하는 data는 이전 값과 다를 경우, 컴포넌트를 리렌더링 하기 때문에 exploreData가 업데이트되었을 때도 새로운 값을 받아올 수 있습니다. 이는 react-query가 내부적으로 상태값을 관리하기 때문입니다.

반면, exploreData는 직접 변경해주는 경우, 이전과 동일한 참조값을 가지기 때문에 변경이 감지되지 않아서 리렌더링이 되지 않게 됩니다. 이를 해결하기 위해서는 exploreData의 참조값이 변경되도록 코드를 작성해야 합니다. 예를 들어, useEffect 훅을 이용해서 exploreData가 변경될 때마다 tweetBox 컴포넌트에게 새로운 값을 전달해주는 방법이 있습니다. 코드로 작성하면 다음과 같습니다.

// useEffect를 이용해서 exploreData가 변경될 때마다 tweetBox에 새로운 값을 전달
useEffect(() => {
  setTweetData(exploreData);
}, [exploreData]);

// tweetBox에 전달할 데이터를 tweetData state로 관리
const [tweetData, setTweetData] = useState([]);

return (
  <>
    {/* ... */}
    {isPeople ? (
      <>
        {tweetData.map((t: any, i: number) => {
          return (
            <TweetBox data={t} key={i} />
          )
        })}
      </>
    ) : (
      <TweetBox data={data.data.data} />
    )}
  </>
);

위 코드에서는 exploreData가 변경될 때마다 tweetData 값을 업데이트해주는 useEffect를 사용하고 있습니다. tweetData 값은 tweetBox 컴포넌트에게 전달되는 데이터로 사용됩니다. isPeople가 true일 때는 tweetData 값을 이용해서 tweetBox를 렌더링하고, 그렇지 않은 경우에는 react-query에서 받아온 data를 이용해서 tweetBox를 렌더링합니다. 이렇게 하면 exploreData가 변경될 때마다 tweetBox에 새로운 값을 전달할 수 있게 됩니다.

=> 여기서 직접 변경되는 경우는 setExploreData 함수를 사용해서 데이터를 변경하는 것을 말한다.

exploreData값을 직접 변경해주는 경우를 set함수를 사용하는 것을 말하는거야?

네, setExploreData 함수를 사용하여 exploreData 값을 변경하는 경우를 말합니다. 이 경우 exploreData의 값이 변경되지만, 이 값이 TweetBox 컴포넌트에 전달되는 prop의 reference에 영향을 주지 않습니다. 즉, TweetBox 컴포넌트는 여전히 이전 exploreData 값을 가지고 있기 때문에 변경된 값이 반영되지 않게 됩니다. 따라서 TweetBox 컴포넌트에 업데이트된 값을 전달하려면 exploreData 값을 변경하는 대신, TweetBox 컴포넌트에 data prop으로 직접 data.data.data 값을 전달하는 방식으로 처리해야 합니다.

정리하자면
1. exploreData를 변경할때 set함수를 사용하더라도 같은 reference를 참조하기때문에 리렌더링이 일어나지 않는다.
2. 따라서 업데이트된 데이터 값을 tweetBox에 prop값으로 넘겨주고 싶으면 prop값으로 data.data.data값을 넘겨주거나(react-query에서는 이전 data값과 다른 경우 컴포넌트를 자동적으로 리렌더링하기때문에)
3. useEffect를 사용해서 setExploreData가 발생될떄마다 리렌더링 발생시키야한다.

확인!

맞습니다! 여러분이 정리한 내용이 맞습니다.

set 함수를 사용하여 exploreData 값을 변경하더라도 이전 reference를 그대로 사용하므로 리렌더링이 일어나지 않습니다.
react-query에서 data 값이 업데이트되면 컴포넌트가 자동으로 리렌더링되기 때문에, 이전과 다른 data 값을 tweetBox에 prop으로 넘겨주는 것으로도 문제를 해결할 수 있습니다.
setExploreData가 호출될 때마다 리렌더링이 발생하도록 useEffect 훅을 사용하는 것도 하나의 방법입니다. 이 경우 exploreData 값이 변경될 때마다 tweetBox 컴포넌트가 업데이트되므로, 항상 최신 데이터를 보여줄 수 있습니다.

profile
프론트엔드 개발 지망생입니다:)

0개의 댓글