React에서 글 작성, 수정, 삭제가 이제 원하는 대로 잘 이루어졌다. 데이터 베이스에도 해당 정보들이 잘 반영이 되었지만 몇 가지 사소한 문제점들이 있었다.
React에서 게시글을 작성, 수정 및 삭제한 후에 백엔드에는 잘 전달되고 데이터 베이스의 영속화는 잘 되었지만, React에서는 실시간으로 반영이 되지 않았다. 처음에는 무식하게 새로고침을 이용해 확인을 했지만, 근본적인 문제해결이 아닌 것 같아 더 공부해 보았다.
Props
React를 rerendering 시키시 위해서는 state값의 변화를 주는 것이 일반적이다. 하지만 문제는 글을 쓰는 post의 컴포넌트와 글을 불러오는 timeline의 컴포넌트 그리고 글 수정 및 삭제의 tweet의 컴포넌트가 각각 달랐다는 점이다.
큰 구조를 보면 다음과 같았다.
Home .tsx ┏ post-tweet-form.tsx
┗ timeline.tsx ━ tweet.tsx
post-tweet-form에서 글쓰기가 완료되거나 tweet에서 수정 및 삭제가 완료되었을 시 timeline에 해당 사항들을 전달할 필요가 있었다. 상태값을 전달해야 하므로 props를 사용해야 했고, props는 오로지 자식에게만 전달 가능하므로 post에서 timeline으로 props를 전달하기 위해선 상태값을 가장 최상위인 Home에 생성해야 했다.
변경 전 home.tsx
import styled from "styled-components";
import PostTweetForm from "../components/post-tweet-form";
import Timeline from "../components/timeline";
import { useState } from "react";
const Wrapper = styled.div`
display: grid;
gap: 50px;
overflow-y: scroll;
grid-template-rows: 1fr 9fr;
`;
export default function Home() {
return (
<Wrapper>
<PostTweetForm />
<Timeline />
</Wrapper>
);
}
Home 아래에 PostTweetForm과 Timeline이 배치되어 있고, home.tsx에 상태값과 그 상태를 변경할 수 있는 함수를 생성한다.
변경 후 home.tsx
import styled from "styled-components";
import PostTweetForm from "../components/post-tweet-form";
import Timeline from "../components/timeline";
import { useState } from "react";
const Wrapper = styled.div`
display: grid;
gap: 50px;
overflow-y: scroll;
grid-template-rows: 1fr 9fr;
`;
export default function Home() {
const [tweetsUpdated, setTweetsUpdated] = useState(false);
const onTweetPosted = () => {
setTweetsUpdated((prev) => !prev) // 상태를 토글하여 현재값에서 반대값으로 변화
};
return (
<Wrapper>
<PostTweetForm onTweetPosted={onTweetPosted} />
<Timeline tweetsUpdated={tweetsUpdated} />
</Wrapper>
);
}
boolean 값을 이용한 tweetsUpdated의 상태를 만들어 주고, onTweetPosted() 함수를 이용하여 값을 변경해 준다. 그리고 PostTweetForm에는 상태를 변경시킬 수 있는 함수 onTweetPosted()를 props로 전달한다. Timeline에는 Home의 상태를 추적할 수 있는 tweetsUpdated를 props로 전달한다. 이제 해당 props를 받은 각각의 컴포넌트 들은 자식의 컴포넌트에서 부모의 함수를 호출할 수 있고, 부모의 상태변화를 자식의 컴포넌트에서 확인할 수 있게 된다.
post-tweet-from.tsx
export default function PostTweetForm({ onTweetPosted }: { onTweetPosted: () => void }) {
...
const onSubmit = async() = {
글쓰기 성공!
onTweetPosted();
}
...
}
post-tweet-form에서 글쓰기가 완료되면 onTweetPosted() 함수를 이용해 부모의 state값을 변경시켜 준다.
timeline.tsx
export default function Timeline({ tweetsUpdated }: { tweetsUpdated: boolean }) {
...
useEffect(() => {
fetchTweets();
}, [tweetsUpdated]);
...
}
timelin에서는 GET요청의 fetchTweets();를 useEffect()의 인자로 부모에서 받은 tweetsUpdated의 상태값을 넣어준다. 따라서 이제 post-tweet-form에서 부모의 값을 변경하면 timeline에서 변경을 감지하고 다시 GET청을 통해 받은 정보를 rerendering 해 준다.
반영이 아주 잘 된다.
수정과 삭제가 있는 tweet.tsx는 현재 timeline 안에 있기 때문에 추가로 Home에 있는 onTweetPosted()도 같이 추가로 timeline에 넘겨준다. 그리고 timeline은 다시 tweet에게 전달해 주면 이제 최하위 자식인 tweet에서도 Home의 상태값을 변경할 수 있다.
추후에는 불필요한 렌더링을 막는 useMemo와 전역 상태관리가 가능한 redux 등의 툴도 사용해 보면서 조금 더 최적화를 해봐야겠다.