[React] 두 번 렌더링 되는 현상 (React.StrickMode)

hyejinJo·2024년 9월 12일
0

React

목록 보기
11/13
post-thumbnail

인스타그램 클론 코딩을 하는 중, 알림 탭에서 오늘 날짜에 해당하는 컨텐츠를 필터링 해서 표시하는 작업을 하고 있었다.

컨텐츠 data 에 map 을 돌려 오늘 날짜에 해당되는 컨텐츠면 todayAlarm 이라는 state 배열에 담아지는 구조로 코드를 구현했는데, 오늘에 해당하는 컨텐츠는 하나임에도 똑같은 컨텐츠가 배열 두 번씩 담기는 것이었다.


function AlarmSidebar({ isOpen }) {
  const alarmData = [
    {
      User: {
        id: 'nawm_eeee',
        nickname: '김진명',
        image: '/user-01.jpg',
      },
      type: 'comment',
      content: '안녕하세요 피드가 예쁘네요!',
      createdAt: new Date(new Date().setDate(new Date().getDate() - 0)), //  오늘
    },
    {
      User: {
        id: 'veenoo',
        nickname: '조수빈',
        image: '/user.jpg',
      },
      type: 'mention',
      content: '이거 봄?ㅋㅋㅋㅋ',
      createdAt: new Date(new Date().setDate(new Date().getDate() - 0)), //  오늘
    },
    {
      User: {
        id: 'h._seung',
        nickname: '랍뷰희승',
        image: '/user.jpg',
      },
      type: 'mention',
      content: '그러자!!',
      createdAt: new Date(new Date().setDate(new Date().getDate() - 12)), // 12일 전
    },
    {
      User: {
        id: 'jin_woo',
        nickname: '김김진진우우',
        image: '/user.jpg',
      },
      type: 'comment',
      content: '잘나왔네',
      createdAt: new Date(new Date().setDate(new Date().getDate() - 7)), // 7일 전
    },
  ]

  const [todayAlarm, setTodayAlarm] = useState([])

  useEffect(() => {
    alarmData.map((data, index) => {
      const currentDay = new Date()

      const day = data?.createdAt
      // 오늘 날짜인지 체크
      if (
        currentDay.getFullYear() === day.getFullYear() &&
        currentDay.getMonth() === day.getMonth() &&
        currentDay.getDate() === day.getDate()
      ) {
        console.log('오늘입니다')
        setTodayAlarm((prev) => [...prev, data]);

      } else {
        console.log('오늘이 아님')
      }
    })
  }, [alarmData.length])

  console.log(todayAlarm)

  return (
    <div
      role="dialog"
      className={cx(style.sidebar, isOpen && style.opened, style.alarm)}
    >
      <div className={style.sidebarInner}>
        <h3 className={style.sidebarTitle}>알림</h3>
        <div className={style.sideBarContent}>
          <h4 className={style.sidebarSubTitle}>
            <span>오늘</span>
          </h4>
        </div>
      </div>
    </div>
  )
}

export default AlarmSidebar

map 이 두 번 돌아가는 것으로 보아 렌더링이 한 번 더 일어난 것으로 예상되었고, 구글링을 해본 결과 그 원인을 알아냈다.

StrictMode

리액트는 StrickMode 옵션이 기본으로 설정이 되어있는데, 해당 옵션이 켜져있을 땐 개발모드에서 렌더링이 두 번씩 실행된다고 한다.
StrickMode 의 역할은 아래와 같이 어떠한 기능 사용에 대한 경고나, 부작용 검사 등이 있다고 한다. 공식문서

  1. 안전하지 않은 생명주기를 사용하는 컴포넌트 발견
  2. 레거시 문자열 ref 사용에 대한 경고
  3. 권장되지 않는 findDOMNode 사용에 대한 경고
  4. 예상치 못한 부작용 검사
  5. 레거시 context API 검사
  6. Ensuring reusable state

이 모드를 해제하려면 next.config.js 에서 reactStrictMode 옵션을 false 로 지정해주면 된다.

하지만 개발 모드에서 진행되는 경고나 검사는 필요하기 때문에 StrictMode 를 해제하는 것은 지양하는 것이 좋다.

위의 방법을 쓰기보단, 오늘에 해당하는 컨텐츠 배열 안에 (두 번째 렌더링 때)똑같은 컨텐츠가 들어가지 않도록 방지하는 쪽으로 수정을 했다. tempTodayAlarm 이라는 임시 배열을 하나 만든 뒤 아래 내용으로 필터링된 값을 다시 setTodayAlarm 의 인수값으로 넣었다.
!tempTodayAlarm.some(alarm => alarm.content === data.content)

useEffect(() => {
    // 오늘 알림을 임시 배열로 수집
    const tempTodayAlarm = [];

    alarmData.map((data, index) => {
      const currentDay = new Date()

      const day = data?.createdAt
      // 오늘 날짜인지 체크
      if (
        currentDay.getFullYear() === day.getFullYear() &&
        currentDay.getMonth() === day.getMonth() &&
        currentDay.getDate() === day.getDate()
      ) {
        console.log('오늘 입니다')
        if (!tempTodayAlarm.some(alarm => alarm.content === data.content)) {
          tempTodayAlarm.push(data);
        }
      } else {
        console.log('오늘이 아님')
      }
    })
    // 상태를 한 번만 업데이트
    setTodayAlarm(tempTodayAlarm);
  }, [alarmData.length])

결과: 오늘에 해당하는 컨텐츠가 정상적으로 한 번씩만 push 된 것을 알 수 있다.

참고:
https://velog.io/@rssungjae/React-%EB%91%90%EB%B2%88%EC%94%A9-%EB%A0%8C%EB%8D%94%EB%A7%81%EB%90%98%EB%8A%94-%EA%B2%BD%EC%9A%B0

profile
Frontend Developer 💡

0개의 댓글