컴포넌트 조건부 렌더링 시 각기 다른 서버 요청을 하고 싶을 때

이은지·2022년 1월 24일
2

인턴회고록

목록 보기
5/6
post-custom-banner

🧐 문제 정의

구조는 다음과 같다

  • 부모 컴포넌트이자 컨테이너 컴포넌트: HomeContainer.js
  • 자식 컴포넌트이자 프레젠테이셔널 컴포넌트: GuestHome.js , OwnerHome.js

HomeContainer.js에서 두 자식 컴포넌트 중 어떤 컴포넌트를 렌더링 할 지 결정한다.
각 자식 컴포넌트는 렌더링 시에 서버에 정보를 요청해야 하는데, 각각 다른 API로 요청을 해야했다.

☝🏻 첫 시도

방식: 각 자식 컴포넌트의 useEffect() 안에 서버에 정보를 요청하는 코드를 넣었다.
문제: 자식 컴포넌트의 useEffect()가 동작하지 않음.

// HomeContainer.js

function HomeContainer () {

  const [showGuest, setShowGuest] = useState(false);
  const [showOwner, setShowOwner] = useState(false);

  (생략) GuestHome, OwnerHome 중에 어떤 컴포넌트를 렌더링할 지 결정하는 로직

  return (
      {showGuest && <GuestHome/>}
      {showOwner && <OwnerHome/>}
  )
}

showGuest, showOwner라는 상태가 업데이트 됐을 때 컴포넌트가 렌더링 되면서 각 컴포넌트의 useEffect가 동작할 거라고 생각했는데, 아무리 해도 상태 업데이트 타이밍에 맞춰서 useEffect 동작이 안됐다.

✌🏻 두번째 시도

How to use useEffect() inside a child component to fetch data?

이 글이 날 구원했어

자식컴포넌트에 복잡한 로직 넣지 않기
자식 컴포넌트에 있는 서버 요청 코드를 부모 컴포넌트로 옮겼더니 바로 문제 해결됐다

// HomeContainer.js

const [showGuest, setShowGuest] = useState(false);

useEffect(() => {
	if (showGuest){
    	서버에 데이터를 요청하는 dispatch
    	}
},[showGuest])

...

return (
{showGuest && <GuestHome/>}
)

// GuestHome.js

HomeContainer에서 보낸 dispatch를 통해 store에 저장해둔 데이터를 불러와서 보여주는 역할만! 
즉, 프레젠테이셔널 컴포넌트로만 작동하게끔.

정확히 왜 안됐는지는 모르겠지만 무튼 부모-자식 컴포넌트가 존재할 때, 특히 부모 컴포넌트의 상태값에 따라 자식 컴포넌트를 조건부 렌더링 하는 경우에는 자식 컴포넌트 안의 useEffect()가 동작을 안한다. 그러니 자식 컴포넌트가 아닌 부모 컴포넌트에서 해당 작업을 진행할 것!

👏🏻 세번째 시도(성공!)

문제: 위 코드의 useEffect가 HomeContainer.js 첫 렌더링 시에만 실행되고, showGuest 상태가 업데이트 됐을 때는 실행되지 않음. => 즉, 서버에 요청이 안감... 😹

useEffect 다루기 너무 어렵다.

그러다가 문득 왜 dispatch를 useEffect 내에서 보냈지 하는 의문이 들어서 코드를 수정했다.

    const data = location.state;
    if (typeof data !== "undefined") {
      if (data.from == "frontdoor" && data.status == 1) {
        dispatch(getGuestInfo(match.params.id)).then((response) => { 
        // Guest임이 확인된 경우 바로 dispatch
          if (response.type == "guest_info_success") {
            setShowGuest(true);
          }
        });
      } else if (data.from == "frontdoor" && data.status == 0) {
      	// owner임이 확인된 경우 바로 dispatch
        dispatch(getOwnerInfo(match.params.id)).then((response) => {
          if (response.type == "owner_info_success") {
            setShowOwner(true);
          }
        });
      } else if (data.from == "register") {
        dispatch(getOwnerInfo(match.params.id)).then((response) => {
          if (response.type == "owner_info_success") {
            setShowOwner(true);
          }
        });
      }
    } else {
    	(생략)
    }
  }, []);

showGuest가 true로 바뀌면 서버에 요청을 전송하는 코드를 다른 useEffect에 넣는 게 아니라, 그냥 guest, owner 를 판단하는 useEffect에 넣어줬다.

같은 코드만 하루종일 쳐다보고 있으니까 내 생각에 갇혔었다. 몇 시간 쉬다가 다시 보니 이렇게 간단한 해결책이!

👍🏻 최종 로직

  1. HomeContainer.js 렌더링 시 useEffect 실행
  2. useEffect 내에서 guest/owner 두 가지 케이스로 분기.
    분기되면 각 케이스에 맞춰 바로 서버에 요청(dispatch)
    또한 showGuest/showOwner 상태를 true로 변경. 이 상태에 따라 GuestHome.js OwnerHome.js 중 하나가 렌더링된다.
  3. dispatch 성공하면 받아온 데이터를 store에 저장
    이때 store는 guest, owner용 store를 각각 따로 두었다.
  4. 프레젠테이셔널 컴포넌트인GuestHome.js OwnerHome.js 는 각기 상응하는 store에서 정보를 가져와 화면에 보여준다.

👀 느낀 점

  • 단순하게 생각할 때 해결책이 나온다.
  • 모든 복잡한 로직은 부모 컴포넌트에서 처리하고, 자식 컴포넌트는 프레젠테이셔널 컴포넌트로 동작하는 패턴이 바람직하다.
  • 라이브러리를 쓰더라도 자바스크립트에 대한 지식이 필요하다는 걸 느꼈다... 인턴 끝나면 공부해야지.

그래도 그냥 혼자 프로젝트 했으면 마주치지도 못했을 문제점을 발견하고, 혼자 끙끙대며 해결해본 과정이 너무 재밌었다 희희 물론 다 해결 됐으니까 재밌다고 할 수 있는 것임.

바쁘더라도 종종 기록해야지!

post-custom-banner

2개의 댓글

comment-user-thumbnail
2022년 2월 10일

프레젠테이셔널 컴포넌트가 단순히 데이터를 받아서 보여주는 역할을 한다는 사실만 기억하셨으면 시간을 아끼실 수 있었을텐데 아쉬워요
그래도 시행착오 공유해주셔서 감사합니다!

1개의 답글