개발새발 로그

몽고DB : Post DB-User DB 연동(author과 ObjectId), useSelector 데이터로딩 방지 본문

MERN

몽고DB : Post DB-User DB 연동(author과 ObjectId), useSelector 데이터로딩 방지

이즈흐 2023. 6. 29. 02:12

이제 리덕스에 로그인 정보를 넣을 수 있게 되었으니 이 유저 데이터를 이용해서 게시글에 업로드한 유저의 이름을 띄우고, 게시글 수정 및 삭제는 작성한 유저만 가능하도록할 수 있다.

 

 

 

1. Upload.js 게시글 등록 페이지 로그인한 유저만 들어오게하기

 

1. Upload.js에서 useSelector을 import하고user데이터 가져오기

2. useEffect로 로그인이 되어있지않으면 막기

 

 

2. 게시글을 업로드하면 유저의 정보도 같이 저장한다.

1. useSelector로 가져온 user의 uid를 게시글 등록할 때 같이 Post 모델에 저장한다.

 -이때 Post에도 user의 uid를 저장할 스키마를 추가해줘야한다.

몽구스의 author과 ObjectId 활용

  -Post 모델에 스키마를 추가해줄 때 author을 사용한다.

 -ObjectId : 몽고DB에 데이터를 저장할 때 별도로 지정하지 않으면 저장되는 유니크한 id다.

-현재 Post DB에서는 유저DB에 있는 데이터를 가져오고 싶은 상황이다. -> 유저데이터를 가져와야 작성자를 출력할 수 있으므로 

-useSelector로 일일이 Post에 작성자를 기입하는 방법도 있지만 몽구스에서는 DB간의 연동을 위해서 아래와 같이 type을 넣는 부분에 mongoose.Schema.Types.ObjectId를 넣게 되면 User DB에 있는 ObjectId와 대응되는 모든 정보 author에 저장되게 된다.

-아래의 예시를 보자 

-즉 author에 User의 _id값을 넣으면 그 데이터에 해당하는 User의 모든 데이터를 저장한다.

2. 서버에서 /submit API ( 게시글 등록 API) 수정

3. 클라이언트에서 넘겨준 user의 uid로 User DB에 있는 해당 유저의 ObjectId를 가져온다.

 -먼저 user의 uid가 추가되었으므로 아래와 같이 바꿔준다.

-보내줄 데이터 temp에 _id 추가해서 몽고DB에 보내준다.

temp를 Post DB에 저장

3. 이제 서버에 게시글 데이터를 요청할 때 연동된 유저아이디를 가져오자

1. 게시글 리스트를 가져오는 /list API와 게시글 상세정보를 가져오는 /detail API를 수정해주자.

 -populate() : DB에 author 저장된 데이터가 있다면  거기에 대응되는 데이터를 찾아서 합쳐주는 역할이다.

-추가한 후 데이터를 요청해보면 아래와 같이 author에 데이터를 채워서 보내준다.

-아래와 같이 author데이터를 넣으면 잘 출력해주는 모습이다.

 

4. 이 데이터를 이용해서 게시글 수정 버튼과 삭제버튼은 작성자만 볼 수 있도록 하자

-Detail.js 게시글 상세페에지에서 useSelector가져온다.

-리덕스의 user.uid와 몽고DB 게시글데이터의 uid가 같으면 수정 삭제버튼을 볼 수 있다.

 

 

 

 

 

💢어려웠던 부분

1. 지금 현재 업로드페이지에서 리덕스의 useSelector가 새로고침을 하면 빈 데이터를 가져오게 된다.

 - 즉 로그인이 되어있음에도 게시그 등록페이지인 Upload.js에 들어가서 새로고침을 하게되면 아래와 같이 빈값을 가져온다.

-리덕스 데이터를 가져왔는데 왜 빈값이냐?

 ->아래에서 이유를 살펴보자

 

리액트 리덕스에서 데이터를 가져오는 시점은 컴포넌트가 렌더링될 때마다 호출되는 `useSelector` 훅을 사용하여 가져옵니다.

`useSelector` 훅은 리덕스 스토어의 상태를 구독하고, 상태가 변경될 때마다 해당 상태를 가져옵니다. 따라서 컴포넌트가 처음 렌더링될 때 `useSelector`를 호출하면, 해당 상태가 업데이트되기 전의 값을 가져올 수 있습니다.

만약 컴포넌트가 처음 렌더링될 때 빈 값으로 가져오는 문제가 발생한다면, 아래와 같은 몇 가지 원인이 있을 수 있습니다.

1. 초기 상태가 비어있는 경우: 리덕스 스토어의 초기 상태가 비어있는 경우, `useSelector`를 호출할 때 빈 값을 가져올 수 있습니다. 이 경우, 초기 상태를 적절하게 설정해주어야 합니다.

2. 데이터 로딩 시간이 필요한 경우: 데이터를 비동기적으로 가져오는 경우, 데이터가 로딩되기 전에 `useSelector`를 호출하면 빈 값을 가져올 수 있습니다. 이 경우, 데이터 로딩이 완료된 후에 컴포넌트를 다시 렌더링하도록 처리해야 합니다. 예를 들어, 데이터 로딩 상태를 관리하는 상태 변수를 추가하여 로딩이 완료될 때까지 로딩 스피너를 표시하고, 데이터가 로딩되면 컴포넌트를 다시 렌더링하도록 처리할 수 있습니다.

3. 비동기 작업의 완료를 감지하는 방법이 부족한 경우: 데이터를 가져오는 비동기 작업이 완료되었음을 감지하는 방법이 충분하지 않은 경우, `useSelector`를 호출할 때 데이터가 아직 업데이트되지 않은 상태일 수 있습니다. 이 경우, 비동기 작업의 완료를 감지하는 콜백 함수나 `useEffect` 훅을 사용하여 데이터가 업데이트되었을 때 컴포넌트를 다시 렌더링하도록 처리해야 합니다.

위의 문제들을 해결하기 위해서는 상황에 맞게 적절한 로직을 구현해야 합니다. 예를 들어, 데이터 로딩 상태를 관리하는 상태 변수를 추가하고, 데이터 로딩이 완료되면 해당 상태 변수를 업데이트하여 컴포넌트를 다시 렌더링하도록 처리할 수 있습니다. 또는 비동기 작업의 완료를 감지하는 콜백 함수나 `useEffect` 훅을 사용하여 데이터가 업데이트되었을 때 컴포넌트를 다시 렌더링하도록 처리할 수도 있습니다.

 

-새로고침을 했을 때 데이터를 처음에는 빈 값을 가져오지만 user데이터의 변경으로 렌더링이 한번 더 요청되어 제대로 된 데이터를 가져온다.

-여기서 우리는 리덕스 데이터를 로딩하는 시간이 필요하다는 것을 알게된다.

 

👍해결방법

1. isLoading이라는 변수를 리덕스 state에 추가해준다.

2. 로그인이 안된 사용자가 Upload페이지에 오는 것을 막을 때 아래와 같이하면된다.

 -이렇게 되면 Login 안한 사용자는 isLoading값이 false이고 user값은 빈값이니까 ! 로 true가 된다. 

그래서 if문을 수행하지않고 useEffect의 dependency의 user를 실행하게된다. ->user값변경되면 재렌더링

이 때문에 다시 isLoading은 true가 되므로 둘다 true가 되어 alert가 실행되게 된다. -> 접근을 막게됨

 

-Login한 사용자는 아래와 같이 처음에는 if문이 false가 되므로 건너뛰고, useEffect의 dependency값으로 재렌더링이된다.

이때 로그인이 되어있으므로 user의 값이 빈값이 아니게 된다. 

그래서 if문을 실행하지 않게되고 Upload페이지에서 새로고침을 하더라도 정상적으로 들어올 수 있게 된다.

 

 

정말 이것때메 고생했다..

이렇게 방어코드 짜는 방식도 항상 생각해야겠다.

 

728x90
반응형
LIST