Karl Hadwen의 insta clone 프로젝트를 참고로 하여 나만의 사진 공유 프로그램을 만들어 보았다. 그리고 그 과정에서 새로 알게된 지식, 디버깅 했던 것들을 정리해보려고 한다.
usePhotos
를 사용해서 photos를 자동 업데이트 하려고 했다.
// App.js
const { user } = useAuthListner();
const { activeUser = {} } = useUser(user?.uid);
const { userId, following } = activeUser;
const [postPhotos, setPostPhotos] = useState([]);
const [orginalPhotos, setOriginalPhotos] = useState([]);
const [userFollowing, setUserFollowing] = useState([]);
const { photos } = usePhotos(userId, following);
useEffect(() => {
setOriginalPhotos(photos);
setPostPhotos(photos);
setUserFollowing(following);
}, [photos, following]);
그런데 이렇게 되면 suggestedProfile에 follow를 눌러도 usePhotos가 실행되지 않는다. 왜냐면 usePhotos는 userId, following을 dependency로 가지고 있기 때문이다. 그말은 following이 바뀌지 않는다는 뜻이다.
following이 바뀌려면 useUser가 바뀌어야 하는데 useUser는 또다시 user.uid를 dependency로 가지고 있기 때문. 따라서 following대신 userFollowing을 pass해주고 follow버튼을 누르면 setUserFollowing을 실행하기로 했다.
그래서 아래와 같이 코드를 바꾸어 주었다.
const [postPhotos, setPostPhotos] = useState([]);
const [orginalPhotos, setOriginalPhotos] = useState([]);
const [userFollowing, setUserFollowing] = useState([]);
const { photos } = usePhotos(userId, userFollowing);
useEffect(() => {
setOriginalPhotos(photos);
setPostPhotos(photos);
}, [photos]);
useEffect(() => {
setUserFollowing(following);
}, [following]);
그럼 userFollowing이 바뀔때 마다 usePhotos가 바뀌고 usePhotos가 바뀌면 originalphotos, postphotos에 새로운 photos가 업데이트 되면서 timeline이 업데이트 된다.
dependency를 잘 생각하고 흐름을 짜니까 userFollowing에 의한 photos 자동 업데이트를 구현할 수 있게 되었다!
Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
UserProfile 컴포넌트에서 위와 같은 warning 이 발생하였다. 말그대로 컴포넌트가 없는 상태에서 state를 업데이트 한다면 메모리 누수가 발생한다는 것이다.
주로 api요청이후 setState를 하는 과정에서 중간에 다른페이지로 navigate되는 경우 메모리 누수가 발생할 수 있다.
이걸 고치려면 useEffect에서 return 값을 정해주어야 한다. 그래야 unmount될때 clean없이 될거니깐.
해법은 여러가지가 있는데 boolean 값을 이용해서 clean up 해주기로 했다.
const [{ profile, photosCollection, followersCount }, dispatch] = useReducer(
reducer,
initState
);
useEffect(() => {
let isMounted = true;
async function getUserPhotos() {
const photos = await getUserPhotosByUserId(user?.userId);
if (photos && isMounted) {
dispatch({
profile: user,
photosCollection: photos,
followersCount: user.followers.length,
});
}
}
if (user) {
getUserPhotos();
}
return () => {
isMounted = false;
};
}, [user?.userId]);
photos를 요청하고 나서 photo가 있고 mount가 되었을때 dispatch를 이용해서 state를 변경해줘야 메모리 누수를 막을 수 있다.
scroll할 대상에 height가 있어야만 overflow되었을때 scroll이 생긴다. Profile페이지 안에서 Post 구현하다가 알게된 사실!
margin auto
값을 쓰면 된다. (display가 block이 된 상태에서만 적용!).content {
display: block;
margin-left: auto;
margin-right: auto
}
//tailwind
<div class="mx-auto">
Apple 클론 할때 잠깐 배운적이 있다.
module.exports = {
theme: {
fill: {
gray: ({ theme }) => theme('colors.gray')
}
}
}
// somewherre.js
<div class='fill-gray'>
요런식으로 설정하고 사용하면 된다!
참고
eslint설치하고 rules에 코드를 맞추지 않으면 컴파일 에러가 난다. eslint 에러는 고스란히 표시하면서 동시에, eslint에 의한 컴파일에러를 막고 싶으면?
아래 링크 참고!
애초에 앱을 만들기 전에 설계에 대해 좀 더 깊이 고민했다면, Post 컴포넌트가 profile, dashboard 두개의 page에서 사용한다는 것을 알고 애초에 post에 관한 context를 App에 설치했을 것이다.
설계에 대해 깊이 고민하자.
이미 만들어져 있는 것을 재사용할 수 있는지 항상 생각!
그래서, POST, PROFILE같은경우는 여러가지 내용이 바뀌더라도 알아볼 수 있는, 정체성을 확인할 수 있는 고유의 id를 가지고 있으면 좋을 것 같다고 생각했다.
data를 설계할 때 참고하자!!
Header 컴포넌트에 getOriginalPhotos가 profile -> dashboard로 넘어갈때 작동안함. (왜냐면, App에 있는 postPhotos state가 업데이트 안되어있으니깐.)
근데 dashboard에서 다시 한 번 로고를 클릭하면 postPhotos state가 업데이트 된다.(react dev tools에서 확인 가능하다.) 근데 A - Post에 좋아요 표시가 안뜬다.
근데 react dev tools을 통해서 A - Post를 보면 좋아요 표시는 되어있다. 업데이트된 state가 진입했다는 뜻이다. 근데 좋아요표시가 화면에 반영안된걸 보니 랜더링 된것 같지는 않다.
Post가 memo되었기 때문에 render되지 않는것인가...
그래서 dashboard에서 로고를 누르고 나서 profile로 갔다가 다시 dashboard로 가면 업데이트된 state대로 랜더링 되어있다.
디버깅
음 그래서 memo를 지우고 다시 똑같이 해보았는데.... 좋아요 표시는 여전히 되지 않았다.. 그럼 memo때문이 아니라는 건데... 뭐때문이지?? 좋아요 버튼을 누르고 나면 postPhotos까지 업데이트 되게 해야하나?? --- postphotos 까지 업데이트 하니 잘된다. 근데 업데이트를 두번 하기에는 좀 그렇다.
해결 방법
아!! 이제 알겠다.... setPostPhotos는 prop으로 넘어오는데 dashboard에서는 Header에 prop으로 넘겨주었으나 profile page에서는 prop으로 넘겨주지 않고 있기 때문에 setPostPhotos가 없는 것이다...
그래서 그냥 아예 독립시키기 위해서 prop으로 넘겨주는 대신 context로 넘겨주기로 했다. 그러니 잘된다.
이렇게 프로젝트를 마무리하고 테스트 코드도 짜보았다. 테스트 코드를 짜면서 겪게된 시행착오또한 상당한데 그 시행착오는 아래 링크를 통해 볼 수 있다.
instacoolike testing TIL