TIL 20211127 [항해99 73일차]

7062 단어 항해99항해99

프로필 수정 후 헤더 사진 변경

카드 프로필을 수정 했을때 사진도 변경이 됐었다면 헤더에 있는 프로필 사진도 변경이 되야하는데 그부분을 전혀 고려하지 않았었다. 헤더 프로필 사진은 새로고침을 해야 변경되서 리덕스가 필요하다는걸 뒤늦게 알게되어 적용하게 됐다. 😂

// 헤더 컴포넌트
  const userInfo = useSelector((state) => state.user);
  const userProfile = userInfo.profile ? userInfo.profile : '';
  ...생략...
 <div>
    <IconButton className="my-page" onClick={moveToMyPage}>
      {userProfile ? (
       <ImageBox className="imageBox" src={userProfile} />
     ) : (
        <HeaderProfileSvg />
     )}
    </IconButton>
 </div>
// 리덕스
// types.js
export const PROFILE_CHANGE = 'user/PROFILE_CHANGE';

// actions.js
const profileChange = (profile) => ({
  type: PROFILE_CHANGE,
  profile,
});

// reducer.js
  case PROFILE_CHANGE: {
   draft.profile = action.profile;
   break;
 }

위에 사진처럼 프로필 사진을 수정할때 사진이 리덕스에 잘 저장되서 작성완료 후 헤더에서 프로필 사진이 새로고침 없이로 바로 변경된걸 확인 할 수 있다.


마이페이지 리덕스 저장소 backCard, backCardId로 변경

고민한 문제: 메인페이지에서 byId, allIds로 서버에서 데이터 가져와서 저장해 놓은 것이 초기화 됨

  • 고민이 발생한 이유
    메인페이지에서 byId, allIds를 서버에서 데이터 가져올때 사용하는데 마이페이지에서도 똑같이 byId, allIds를 사용해서 메인페이지 데이터가 초기화되는 문제가 발생했다.

  • 해결방안
    서버에서 받아온 데이터를 메인페이지에서 byId, allIds 방식을 사용해서 저장했는데 그렇게 저장을 해야지만 byId, allIds 방식이 사용되는줄 알고 마이페이지에서 서버 데이터를 가져올때도 byId, allIds로 저장했었다. 근데 이게 이름인 byId, allIds로 방식을 정하는게 아닌 객체{}, 배열[]로 구분되서 저장되면 되는거였다...😂

    즉 byId, allIds 이름이 변경되도 객체와 배열만 잘 선언해주면 똑같은 방식으로 사용할 수 있다.

const initialState = {
// byId: {}, allIds: [] 에서 backCard:{}, backCardIdx:[]로 이름 변경
  backCard: {},
  backCardIdx: [],
};

 [LOAD_MY_CARD]: (state, action) =>
      produce(state, (draft) => {
        draft.backCard = {};
        draft.backCardIdx = [];
        const { card } = action.payload;
        const cardList = card.cardDtoList;
        draft.current = card;
        // draft.cardList = cardList;
        cardList.forEach((doc) => {
          draft.backCard[doc.cardId] = doc;
          draft.backCardIdx.push(doc.cardId);
        });
      }),
    [CREATE_CARD]: (state, action) =>
      produce(state, (draft) => {
        const { cardId } = action.payload.card;
        draft.backCard[cardId] = action.payload.card;
        draft.backCardIdx.unshift(cardId);
      }),
    [UPDATE_CARD]: (state, action) =>
      produce(state, (draft) => {
        // draft.current = action.payload;
        draft.backCard[action.payload.card.cardId] = action.payload.card;
      }),
    [DELETE_CARD]: (state, action) =>
      produce(state, (draft) => {
        delete draft.backCard[action.payload.cardId];
        draft.backCardIdx = draft.backCardIdx.filter(
          (id) => id !== Number(action.payload.cardId),
        );
      }),

리듀서에서 초기화 설정에서 backCard: {}, backCardIdx: []로 선언해주고, 마이페이지에 관련된 CRUD에서 byId, allIds로 사용한 것들을 backCard, backCardIdx로 변경해서 문제를 해결했다.

리덕스에서 byId,allIds 방식을 사용했던 이유

많은 애플리케이션은 본질적으로 중첩되거나 관계형인 데이터를 처리한다. 예를 들어, 블로그 편집자는 많은 게시물을 가질 수 있고, 각 게시물에는 많은 댓글이 있을 수 있으며, 게시물과 댓글은 모두 사용자가 작성한다. 이러한 종류의 애플리케이션에 대한 데이터는 다음과 같을 수 있다.

const blogPosts = [
  {
    id: 'post1',
    author: { username: 'user1', name: 'User 1' },
    body: '......',
    comments: [
      {
        id: 'comment1',
        author: { username: 'user2', name: 'User 2' },
        comment: '.....'
      },
      {
        id: 'comment2',
        author: { username: 'user3', name: 'User 3' },
        comment: '.....'
      }
    ]
  },
  {
    id: 'post2',
    author: { username: 'user2', name: 'User 2' },
    body: '......',
    comments: [
      {
        id: 'comment3',
        author: { username: 'user3', name: 'User 3' },
        comment: '.....'
      },
      {
        id: 'comment4',
        author: { username: 'user1', name: 'User 1' },
        comment: '.....'
      },
      {
        id: 'comment5',
        author: { username: 'user3', name: 'User 3' },
        comment: '.....'
      }
    ]
  }
  // and repeat many times
]

데이터 구조가 약간 복잡하고 일부 데이터가 반복된다. 이것은 여러 가지 이유로 우려된다.

  • 데이터 조각이 여러 곳에 중복되면 적절하게 업데이트되었는지 확인하기가 더 어려워진다.
  • 중첩 데이터는 해당 리듀서 로직이 더 중첩되어야 하므로 더 복잡해야 함을 의미한다. 특히, 깊게 중첩된 필드를 업데이트하려고 하면 매우 빠르게 추악해질 수 있다.
  • 변경할 수 없는 데이터 업데이트는 상태 트리의 모든 조상도 복사 및 업데이트해야 하고 새 개체 참조로 인해 연결된 UI 구성 요소가 다시 렌더링되기 때문에 깊이 중첩된 데이터 개체에 대한 업데이트는 완전히 관련 없는 UI 구성 요소를 강제로 다시 렌더링할 수 있다. 표시하는 데이터가 실제로 변경되지 않은 경우에도 렌더링한다.

이 때문에 Redux 저장소에서 관계형 또는 중첩 데이터를 관리하는 데 권장되는 접근 방식은 저장소의 일부를 마치 데이터베이스처럼 처리하고 해당 데이터를 정규화된 형식으로 유지하는 것이다. 그게 바로 byId: {}, allIds: [] 방식이다.

P.S. 참고 : https://redux.js.org/usage/structuring-reducers/normalizing-state-shape



오늘은 몰랐던 새로운 사실들을 몇가지 알게되서 많이 도움되고 광명 찾은 기분이라 해피하다. 🤗 먼저, 헤더 프로필 변경부분에서 리덕스 추가가 필요한 이유는 원래 authorize에서 값을 가져와서 authorize을 이용하려 했지만, 이미지만 변경하고 싶은데 파라미터가 3개 있어서 파라미터에 지정된 3가지 값들이 모두 적용되야 한다는걸 알게됐다.(즉 이미지말고 다른값 변경도 같이 보내야 하는 상황) 그래서 새로운 리덕스 PROFILE_CHANGE를 추가해 이미지만 변경될 수 있도록 적용했다.
byId, allIds같은 경우 마이페이지와 메인페이지가 겹치는데 겹치면 메인페이지에 저장했던 값들이 마이페이지에서 사용하게되서 초기화 되는 문제가 발생하는걸 알게되면서 byId, allIds이름은 변경가능하고 배열과 객체로만 선언해주면 된다는 걸 알았다.

좋은 웹페이지 즐겨찾기