본문 바로가기

Project Log/RoomieSeoul

[front-end] 글 올리기 페이지 구성하기

후 드디어 글 올리기 페이지 컴포넌트 만들기가 끝났다! 아오 너무 지긋지긋했다. 지겨우면 다른 페이지도 좀 만들고 해야하는데 흐름 끊길까봐 계속 붙잡고 만들었다.

 

아직 다음 step으로 넘어갈 때 필수 값 입력하게 해야한다거나 유효하지 않은 값 예외처리는 해야하지만 어쨌든 거의 다 끝난 것 같아 속이 후련하다.

 

페이지를 어떻게 구성할까 고민 많이했는데 워낙 입력하는 값이 많다보니, 한 페이지에서 스크롤바로 내려가면서 입력하는 것 보다 단계별로 나눠서 카드 형식으로 만드는게 더 나을 것 같았다. 카드형식으로 했을 때가 절차가 짧은 느낌도 나고 한 단계씩 클리어하는 느낌으로 쓸 수 있을 것 같았다.

 

각 단계별로 컴포넌트를 나눠서 만들었는데, 한페이지에서 모든 컴포넌트를 쫙 뿌려주는 것보다 상태관리하는게 더 복잡했다.

카드 형식이 아니였다면 그냥 제출버튼을 누르는 단계에서 유저가 입력한 값을 모두 가져온 다음 넘기면 됐었는데, 카드 형식은 값을 이미 입력하고 다시 이전 단계를 눌러서 되돌아 갔을 때 이전에 입력했던 값을 가지고 있었어야해서 미리 store에 필요한 값들을 넣어놓고 사용자가 input태그에서 값을 수정하면 다음단계/이전단계 버튼을 눌러 넘어갈 때마다 값들을 업데이트해주었다. 그리고 이미 지나친 단계로 다시넘어올때는, 각 컴포넌트 state의 초깃값으로 스토어있는 props를 넣어주어서 input 태그에서 보이게끔 해주었다.

 

그리고 currentStep이라는 상태값을 이용해서 다음단계로 넘어갈 때는 사용자가 입력한 값을 입력하고, currentStep+1 해주거나 currentStep-1 해주어서 각 단계 별로 맞는 컴포넌트를 뿌려주도록 했다.

 

시연영상

 

영상을 2배속으로 돌려서 그런지 화질이....암튼 백엔드 쪽은 아직 만들지 않아서 최종 제출버튼은 동작하지 않는다.

 

주소 입력은 주소 검색 div를 누르면 다음 주소검색 컴포넌트가 뜨도록 해서 검색할 수 있게 만들었다. 다만 컴포넌트로 넣었을 때 콘솔창에 아래와 같은 경고 메세지가 떴다.  

 

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates memory leaks in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.

 

<div className = {cx('searchDiv')} onClick = {handleShowAddSearch}>
{(fullAddr === '')? (<span>주소 검색</span>) : (<span>{fullAddr}</span>)}
</div>

{addSearchVisible? (
  <div className = {cx('daumSearch')}>
    <DaumPostCode
    onComplete = {handleAddress}
    autoClose = {true}
    />
  </div>
) : null}

 

경고메세지는 unmount 된 컴포넌트에서 setState를 시도하기 때인데, 나의 경우는 DaumPostCode 컴포넌트 때문에 발생하였다.  상위 div를 클릭하면 handleShowAddSearch가 실행되어 addSearchVisible state를 true로 바꿔서 addSearchVisible = true 일때만 아래의 컴포넌트들이 보여질 수 있도록 하였다. 그리고 <DaumPostCode>에서 autoClose={true}를 주어 주소 검색이 완료되었을 때 <DaumPostCode> 컴포넌트의 내부에서 setState를 이용해 display: none으로 바꾼다. 하지만 이미 검색이 끝난 시점에 onComplete = {handleAddress} 내부에서 this.setState({addSearchVisible: false})로 현재 컴포넌트의 state를 변경 해주기 때문에 addSearchVisible=false가 되어 <DaumPostCode>는 mount가 안된다. 하지만 그제서야 <DaumPostCode> 내부에서 autoClose를 위해  setState({ display: 'none' })을 해주기 때문에 이러한 경고 메세지가 발생하였다.

 

검색해보니 이럴때는 아래 코드와 같이 _isMounted 같은 이 컴포넌트가 mount된건지 안된건지 체크할 수 있는 플래그를 만들어서 componentDidMount() {} 안에서 isMounted를 true로 바꿔주고, isMounted가 true인 상태일 때만 원하는 동작을 할 수있도록 하는 것 같았다.

class Page extends Component {
  _isMounted = false;

  state = {
    isLoading: true
  }

  componentDidMount() {
    this._isMounted = true;
  
    callAPI_or_DB(...).then(result => {
      if (this._isMounted) {
        this.setState({isLoading: false})
      }
    });
  }

  componentWillUnmount() {
    this._isMounted = false;
  }

  render() {
    return (
      <div>Whatever</div>
    );
  }
}

export default Page;

 

 

나같은 경우에는 <DaumPostCode>의 상위 컴포넌트에서 어차피  addSearchVisible의 상태 값이 true냐 false냐 에 따라 display여부를 결정하기 때문에 autoClose를 사용하지 않게 수정하였다.

 

<div className = {cx('searchDiv')} onClick = {handleShowAddSearch}>
	{(fullAddr === '')? (<span>주소 검색</span>) : (<span>{fullAddr}</span>)}
</div>

{addSearchVisible? (
  <div className = {cx('daumSearch')}>
  <DaumPostCode
  onComplete = {handleAddress}
  />
</div>
) : null}

 

편-안

 

이제 필요한 값이 모두 입력되지 않은 상태에서 다음단계로 넘어가려고하면 사용자에게 알려주는 alert 모달을 만들고, 숫자가 필요한 곳에 문자나 다른 특수문자가 들어오지 못하게 한다던지, 주소 값으로 서울이 아닌 지역의 값(Roomie Seoul이니까...)이 들어오면 사용자에게 재 입력을 요청하도록 예외처리를 할 것이다. alert 모달 같은 경우에는 아직 모달로 할지 아니면 화면 어딘가에 글자로 값 입력을 요청할지 고민중이다. 

 

모든 소스는 깃허브에서 볼 수 있다. 👉 theJunimo/RoomieSeoul