[typescript / redux / react] 클라이언트 사이즈 확인, 실시간 리사이징 상태 변경에 대한 삽질 기록
Project

[typescript / redux / react] 클라이언트 사이즈 확인, 실시간 리사이징 상태 변경에 대한 삽질 기록

반응형

현재 프로젝트를 리팩토링 하면서 새로운 기능을 추가 했는데 이를 구현하면서 생긴 문제에 대해 포스팅하고자 한다.

 

목적

 

리팩토링을 하면서 웹 / 태블릿 / 모바일 총 3가지 사이즈로 분기를 해서 구현을 하고 있다.

최종 결과물인 위 움짤과 같이 웹 ui에선 모달로 노출이 되고, 모바일 / 태블릿 ui에선 에러 문구가 노출 되는 기능을 구현하고 싶었다.

 

해당 페이지의 컴포넌트에서는 변경되는 클라이언트의 사이즈를 실시간으로 확인하고,

사이즈에 맞게 webError 상태, resError 상태( 1024px 이하 모바일, 태블릿) 를 변경하여 노출하는 로직을 생각했다.

 

클라이언트의 사이즈가 변경될때마다 리듀서에서 관리하는 pageWidth의 상태도 즉시 변경 되길 원했다.

또한 사이즈마다 작동중인 에러가 다른 사이즈로 변경될 때에는 초기화되는 기능도 필요했다.

 

우선 클라이언트의 사이즈를 체크하기 위한 방법을 찾았는데 2가지로 나눌 수 있었다.

 

let first = document.documentElement.clientWidth;

let second = window.innerWidth;

 

 first 형식으로 사용했을 땐 실제로 크롬 클라이언트의 사이즈와 15px차이가 났었고, second는 크롬 노출 사이즈와 동일하게 출력되는 것을 확인하고 후자의 형식으로 코드를 작성했다.

반응형

pageWidthReducer.ts

import { createSlice } from "@reduxjs/toolkit";

const initialState = {
  width: window.innerWidth,
};

const pageWidthSlice = createSlice({
  name: "pageWidthSlice",
  initialState,
  reducers: {
    changeCurrentPageWidth(state, action) {
      const clientWidth = action.payload;
      state.width = clientWidth;
    },
  },
});

export const { changeCurrentPageWidth } = pageWidthSlice.actions;

export const pageWidthReducer = pageWidthSlice.reducer;

pageWidth는 회원가입 페이지 뿐만이 아니라 모든 페이지에서 확인하고 사용해야 할 상태값이라고 판단했고, 리듀서에 상태값을 추가했다.

 

그리고, 최상위 컴포넌트 App 내에 useEffect로 실시간 변화가 일어나는 지 확인을 해 봤는데.. 별도 리스너 없이는 작동이 불가했다.

 

어떤 방법이 있을까 고민하던 찰나에 setInterval 메소드로 실시간으로 일정 시간마다 사이즈를 체크하여 리듀서에 있는 pageWidth의 상태를 변경시켜주는 방법이 생각 났다.

 

import { changeCurrentPageWidth } from "../src/reducers/pageWidthReducer";
import { connect } from "react-redux";

function App({ modifyCilentWidth }: any) {
  const dispatch = useDispatch();
  let searchPageWidthLoop = () => {
    modifyCilentWidth(document.documentElement.clientWidth);
  };

  let searchPageWidth = window.setInterval(searchPageWidthLoop, 400);
  
  ......
 }
 
const mapDispatchToProps = (dispatch: any) => {
  return {
    modifyCilentWidth: (width: number) =>
      dispatch(changeCurrentPageWidth(width)),
  };
};

export default connect(null, mapDispatchToProps)(App);

 

크롬 리덕스 툴을 통해 확인했을 때 실시간으로 사이즈를 체크하고 상태가 변경되는 걸 확인할 수 있었다.

하지만, 400 밀리세컨드마다 무한 작동되기 때문에 비효율적이고, 디버깅하기 좋지 않은 코드임을 깨달았다.

 

그리고 찾은 방법은 리사이징 이벤트리스너였다. 

 

function App({ modifyCilentWidth }: any) {
  const dispatch = useDispatch();

  useEffect(() => {
    const resizeListener = () => {
      modifyCilentWidth(getWidth());
    };
    window.addEventListener("resize", resizeListener);
  });

  const getWidth = () => window.innerWidth;
  
  return (
    ...
  )
}
  
const mapDispatchToProps = (dispatch: any) => {
  return {
    modifyCilentWidth: (width: number) =>
      dispatch(changeCurrentPageWidth(width)),
  };
};

export default connect(null, mapDispatchToProps)(App);

 

resize 이벤트를 적용해 윈도우의 사이즈가 변경될때마다 리듀서에 담긴 pageWidth의 상태가 변경되도록 구현했고 정상 작동 됨을 확인했다.

 

포스팅을 하고나니 정말 간단한 해결 방법인데 이를 찾기까지 몇시간의 삽질이 있었는지 모르겠다.

resize 리스너를 구글링 해봤다면 간단하게 해결됐을 문제인데, 가지고 있는 지식 경계 안에서만 답을 찾으려고 했던 게 삽질의 이유였던 것 같다.

 

구글링의 중요성을 다시 한 번 느끼며.. 포스팅을 마친다. 

반응형