팝업을 쓰다보면 이벤트의 반응이 팝업에 즉시 반영되도록 해야하는 경우가 있다

 

 

예를 들면, 위와 같이 필터를 클릭했을 때, 나머지 필터들을 흑백처리해 시각적으로 강조하고 싶을 수 있다

 

팝업을 직접 만들어 사용하면 별 문제 없겠지만, 난 귀찮아서 써본적있는 sweetalert2를 대충 적용했고, 여기서부터 문제가 발생했다. (그때는 spring에 jsp로 프론트를 뿌리고 있었으니까...)

 

Filter를 저장하는 state는 상위 컴포넌트에 있고 Swal.fire로 html을 쏴주면 팝업이 정상적으로 뜨는데, 팝업 내부에서 클릭을 해도 팝업이 변하지 않는다.

그런데 팝업 뒤에서 페이지에는 필터가 적용되고 있었다. 이벤트는 정상적으로 발생했는데 Swal의 팝업만 업데이트가 되지 않는 것이다.

 

대충 알아본 원인은 SweetAlert 팝업 내부는 호출한 상위 React 컴포넌트와 따로 life cycle을 가진다는 것? (부정확할 수 있음)

아무튼 상위 컴포넌트에서 state가 변해도 SweetAlert html 변화에 따른 re-render가 발생하지 않는다는게 문제점이다.

 

그럼 해결법은 간단하다. SweetAlert 내부에도 re-render 이벤트를 만들어버리면 된다

 

https://codesandbox.io/s/fork-sweetalert-react-e6utz0?file=/src/index.js 

 

fork-sweetalert-react - CodeSandbox

fork-sweetalert-react by natonato using react, react-dom, react-scripts, sweetalert2, sweetalert2-react-content

codesandbox.io

 

위 예제 샌드박스를 보면 state를 각각 관리하고 있다 (대충 긁어왔더니 react가 많이 구버전...)

상위 컴포넌트인 App에 count가 하나

this.state = {
  count: 0
};

SweetAlert에 html으로 사용되는 Count 컴포넌트에도 count가 하나

this.state = {
  count: this.props.count
};

그리고 SweetAlert를 사용할 때, Count 컴포넌트에 App의 count와 setCount를 넘겨준다

MySwal.fire({
  title: "react swal",
  html: (
    <Count
      count={this.state.count}
      onChangeValue={(value) => {
        this.setState({ count: value });
      }}
    />
  )
});

Count에선 받은 App의 count로 자기 count를 초기화하고, setState도 자기 state와 받은 App의 함수를 같이 호출해준다

onClick={() => {
  this.setState({ count: this.state.count + 1 });
  this.props.onChangeValue(this.state.count + 1);
}}

 

팝업과 본문 실시간 업데이트

즉, re-render를 위해 Count에도 똑같은 state를 설정하고 상위 App 컴포넌트의 state와 동기화를 맞춰주는 방식이다.

 

솔직히 귀찮다. 필요없는 state와 동기화 로직을 추가해야 하기도 하고, props가 많아질수록 답이 안나오는 작업이 될 것 같다.

 

이미 SweetAlert를 여기저기 static한 팝업에 때려박아서 어떻게든 활용하고자하는 사람이 아니라면, 직접 만들거나 React에 최적화 잘 된 다른 좋은 팝업 패키지를 찾아보는게 어떨까 싶다. 복잡한 팝업일수록 더더욱.

+ Recent posts