본문 바로가기

React/Link-Developer

[Link Developer] HOC로 반환된 컴포넌트의 props undefined 이슈

오류 발견

MyProfile 페이지에서 발견된 에러이다.

props에 저장된 로그인한 유저의 id를 조회하여 백엔드로 API 요청을 보낸다.

백엔드에서는 요청받은 id를 DB에서 찾은 뒤 해당 user에 객체를 클라이언트로 응답한다.

 

위 처럼 구상했었지만 props가 undefined 에러가 출력된다.

오류 분석 및 원인

useEffect(() => {
    const userId = props.user.userData._id
    let body = {
        _id: userId
    }

    axios.post('/api/users/profile', body)
    }

 

위 useEffect는 리액트 라이프 사이클에서 컴포넌트가 마운트된 직후 그러니깐 componentDidMount 단계에서 props를 호출하였기 때문에 오류가 난다.

componentDidMount 단계에서는 아직 props를 업데이트를 하지않는다. 그렇기 때문에 props를 호출하면 undefined 오류가 나는 것이다.

 

가장 큰 문제는 유저의 프로필 데이터를 가져오는 로직이라 유저 데이터의 종속된 모든 코드들이 영향을 미친다.

오류 해결

1차 개선 코드

useEffect(() => {
      if (!props.user.userData) {
            return
      }
    
      const userId = props.user.userData._id
      let body = {
          _id: userId
      }
    }, [props.user]

    axios.post('/api/users/profile', body)

 

componentDidMount 단계에서 useEffect를 호출하면 가장 먼저 if(!props.user.userData)를 체크하여 props가 업데이트 되었는지 안되었는지 판별하고 업데이트 되어있지 않다면 retrun한다.

 

이후 props업데이트 되었을때 다시 useEffect를 호출 시키기 위해 의존성 배열에 [props.user]를 설정하여 props.user가 업데이트 되면 다시 실행되게한다.

결과는 성공적으로 props가 업데이트된 뒤에 useEffect가 호출되어 user의 정보를 가져올 수 있게되었다.

하지만 문제점은 useEffect를 두번 실행된다는 것이다.

 

2차 개선 코드

useEffect(() => {
      const userId = window.localStorage.getItem("userId");

      let body = {
          _id: userId
      }
    }

    axios.post('/api/users/profile', body)

 

2차 개선코드에서는 브라우저에 저장된 localStorage의 userId를 조회하여 API 요청을 보낼 수 있도록 하였다.

React 컴포넌트의 렌더링과는 상관이 없어 componentDidMount 단계에 바로 API 요청을 보낼 수 있고 useEffect를 두번 호출하지 않아 좀 더 개선되었다.

 

3차 개선 코드

const userInfoList = useSelector(state => state.userInfo.userListData);

useEffect(() => {

        getProfilePost()
    }, [])

    const getProfilePost = () => {
        if (!userInfoList) {
            dispatch(userInfo())
        }
        else {
            infoFilter(userInfoList.userList)
        }
    }

 

유저의 데이터가 3개 이상의 컴포넌트에 쓰여 props로 관리하기 보다 Redux를 사용하여 관리하는게 효율적이게 되었다.

Profile 컴포넌트에서 필요한 데이터는 로그인한 해당 유저의 프로필 데이터만을 필요로한다.

문제는 전체 user의 데이터만을 Redux store에 저장한다.

 

이를 개선하기 위해 localStorage에 있는 userId를 조회하여 전체 user의 데이터에서 localStorage에 있는 userId와 동일한 id를 가지는 객체만을 가져와야한다.

 

const infoFilter = (userList) => {
	const MyId = window.localStorage.getItem('userId')
        
        const result = userList.filter(element => {
            return element._id === MyId
        })

        setProfile({ ...result[0] }) // setState()
}

 

Store에 저장된 전체 user의 데이터를 자신에 ID에 맞는 데이터를 filter 시켜 useState를 설정한다.

props 업데이트에 영향을 받지않고 2차 개선코드에서 컴포넌트 렌더링 할때마다 API 통신을 하여 리렌더링되고 시간이 걸렸지만 useSelector를 사용하여 변경점이 없다면 API 통신을 하지않는다.

 

 

'React > Link-Developer' 카테고리의 다른 글

Axios 요청을 미친 듯이 보내는 현상  (0) 2021.06.22