Projects/세계 여행 지도

02. 컴포넌트화를 통한 호버링 하이라이트 (feat. Styled Component)

Hov 2021. 6. 3. 21:33

함수형 컴포넌트 vs 클래스형 컴포넌트

 이 전에는 함수형과 클래스형 컴포넌트의 차이를 몰랐다. (그냥 같은 것을 다르게 표현 한 건 줄만...) 현재 리액트 공식 문서에서는 두가지의 이유로 클래스형 컴포넌트보다 함수형 컴포넌트와 훅을 함께 사용하는 것을 권장한다.

1. 편리한 선언

2. 메모리 자원을 덜 사용함
   - 함수형은 상태를 저장할 수 없어서 한번 실행되고 나면 가비지 컬렉터에 의해 메모리 상에서 사라진다.
   - 상태를 저장할 수 없기 때문에 클로저 원리를 이용한 useState 훅을 이용해서 state를 저장한다고 한다.

이러한 점들을 알게 되어서 이번에는 함수형 컴포넌트로 앱을 구성했다. 그리고 나중에 React와 Hook의 동작원리에 대해 한번 공부해보고싶다는 생각이 들었다..!

지난 포스팅의 방법을 통해 지도상의 위도, 경도별로 (180 x 90) 나라 이름을 담은 json파일을 만들었다.
그리고 각 픽셀을 Grid라는 컴포넌트로 만들어, 해당 정보가 담긴 이중배열을 map으로 해당 컴포넌트를 생성했다.

그리고 유저가 마우스를 나라위에 올렸을 때, 해당 픽셀만 하이라이트가 되는 것이 아니라, 그 나라의 모든 픽셀들이 하이라이트가 되어야 하므로, 현재 마우스가 올려 져 있는 country와 주소가 같은지 point라는 이름의 변수와 country를 변경 하는 함수인 setCountry를 props로 전달해준다.

GridMap.jsx

const WorldMap = () => {
  const { userListObj } = useSelector(state => state.map);
  const [ country, setCountry ] = useState(null);
  
  const generateMapGrid = () => {
    return worldgrid.map((r, i) => <MapDiv key = {i}>
     {
       r.map((geo, j) => {
        if(userListObj[geo]) {
          return <Grid key={i + ','+ j} address={geo} visited={userListObj[geo]} point = {country === geo} setCountry={setCountry}></Grid>
        } else {
          return <Grid key={i + ','+ j} address={geo} point = {country === geo} setCountry={setCountry}></Grid>
        }
        
       })
     }
    </MapDiv>);
  }
  return <MapWrapper> {generateMapGrid()} </MapWrapper>;
}

 

Styled-component

각 컴포넌트별로 point라는 변수에 따라 스타일을 쉽게 변경해주기 위해 styled-component를 사용했다.

 뿐만아니라 styled-compoent는 css 파일을 밖에 두지 않고, 컴포넌트 내부에 넣기 때문에, css가 전역으로 중첩되지 않도록 만들어주는 장점도 있다. 

 

Grid.jsx

import styled from 'styled-components';

const Sea = styled.div`
  background-color: white;
  width: 10px;
  height: 10px;
  cursor: default;
  opacity: 0;
`
const Land = styled.div`
  background-color: #3C6B40;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  cursor: pointer;
  position: relative;
  opacity: ${props => (props.point || props.visited) ? "1" : "0.1"};
`

const Grid = ({ address, visited, setCountry, point }) => {
  return (address === 'Sea')
  ? 
    <Sea/>
  : 
    <Land
      point={point}
      visited={visited}
      onMouseOver={() => !point && setCountry(address)}
    >
    </Land>
}

...

 

마우스 호버링을 하면 그 나라에 해당하는 모든 픽셀들이 하이라이트된다!

 

 프로젝트를 되돌아보면서 작성하는 글이라 많이 빈약한 것도 있지만 이번 포스팅은 다음 포스팅에서 본격적으로 렌더링 최적화를 다루기위해 작성한 글이다. 현재의 구현방법으로는 마우스 호버링에 의한 하이라이트가 느리게 반응한다. 다음 글 부터 이러한 문제의 원인을 파헤쳐서 해결하는 글을 작성해보겠다!