1시간만에 뚝딱 다크모드 만들기 - 플리맨 프로젝트

김철기·2022년 12월 15일
7

플리맨(FleaMan)

목록 보기
5/14
post-thumbnail

해당 포스팅은 플리맨(FleaMan) 프로젝트의 광고 겸 개발일지입니다.
시간되실때 플리맨(https://fleaman.shop) 서비스 한번 사용해주시고 피드백주시면 감사하겠습니다.

갑자기 다크모드?

지난번 DNS와 포트포워딩 내용에 이어 오늘은 다크모드다. 너무 맥락이 없지만.. "쉽게 따라하는 쇼핑몰 만들기"같은 시리즈가 아니니까 상관없다고 생각한다. 앞으로도 생각이 정리되는대로 도움이 될만한 정보를 빠르고 쉽게 전달하려고 노력할 것이다. 다크모드는 사실 아주 급한 개발이슈는 아니었다. 그런데 컨텐츠 개발을 하면서 생각보다 쉽게 개발할 수 있겠다는 생각이 들어 뚝딱 해버렸다. 실제로 1시간정도 소요된 것 같다.

뭘로 만들까?

본인은 프론트엔드 개발자가 아니다. 플리맨 서비스를 사용해본 독자라면 허접한 UI와 난잡한 렌더링에서 이미 느꼈을 것이다. (그렇다고 아주 못봐줄정도는 아니다) 아무튼 하고 싶은 얘기는 프론트엔드 개발자도 아닌 사람이 뚝딱 만들었으니 정답이 아닐수 있다는 것이다. 하지만 플리맨에서 잘 동작하고 있으니 한번 공유해보겠다. 참고로 플리맨의 프론트엔드는 React.js로 구현되었다.

Redux

모드를 결정하는 변수는 바뀔때마다 렌더링될 수 있는 state여야하고, state는 특정 컴포넌트에 종속된 state가 아니라 전역으로 사용할 수 있는 state여야된다.

모드 변경 버튼을 누르고 새로고침을 해야 적용이 된다면 매우 심한 욕을 먹을 수 있고, 메인 페이지는 다크모드인데 로그인 페이지는 라이트모드면 이 또한 매우 심한 욕을 먹을 수 있기 때문이다.
그래서 Redux를 사용했다. 이게 아니라면 useState로 정의한 뒤 컴포넌트에서 계속 상속받아서 사용했어야할 것이다. Redux를 만들어주신 개발자분에게 감사하다. 로컬스토리지를 사용할수도 있겠지만 앞서 말했듯이 state가 아니라 자동으로 렌더링되지 않아서 못쓴다.

Local Storage

로컬스토리지 못쓴다고 했는데 바로 이어서 쓴다. 정신이 오락가락하는 것이 아니고 state로는 못쓰지만 다른 용도로 써야해서 그렇다. 로컬스토리지는 다음번에 다시 접속했을 때 모드를 유지하기 위해 저장하는 용도로 사용한다.

버튼 onClick

사용자가 모드를 바꾸는 방법을 여러가지 제시할 수 있겠지만 플리맨은 가장 보편적인 버튼형태로 제공한다. 버튼을 누르면 모드가 바뀌는 형태이다.

styled-components

CSS를 효율적으로 작성할 자신이 없어서 하나하나 style={{}} 쓸까했지만 styled-components라는 편리한 스타일 지정방법이 있어서 사용했다. Redux에 이어 감사하다.

어떻게 만들었을까?

Redux - store.js

store.js는 라이브러리가 아니라 내가 지은 파일명이다. 간단하게 코드를 한번 보자.
일반적인 Redux 코드이다. name에 사용할 state명 적고 initialState에 초기값으로 사용할 값을 정의한다. 플리맨은 기본이 다크모드이기 때문에 로컬스토리지에 값이 없으면 다크모드가 기본 값으로 정의된다.(원래 라이트였는데 다크를 더 좋아하더라..)
changeBg() 부분은 state를 다룰수 있는 함수이다. dark, light로 값을 바꾸기만 하면돼서 받아온 값(payload)로 값을 바꾸는 동작만 한다.
나머지 부분은 Redux는 원래 저렇게 쓰는거라서 쓴거다.

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

let bg = createSlice({
  name: 'bg',
  initialState: localStorage.getItem('mode') != undefined ? localStorage.getItem('mode') : 'dark',
  reducers : {
    changeBg(state, a){
      return a.payload
    }
  }
})
export let { changeBg } = bg.actions 
export default configureStore({
  reducer: {
    bg: bg.reducer
  }
})

Redux, Local Storage, 버튼 onClick

그러면 만든 state를 어떻게 불러다 쓰는지 보자.
useSelector를 저렇게 쓰면 내가 만든 bg라는 state를 가져올 수 있다. 그리고 Button의 onClick이벤트에서는 useDispatch로 만들어둔 changeBg와 로컬스토리지 저장을 적절하게 실행시키면 모드가 dark <-> light로 토글 및 저장된다.

import { useDispatch, useSelector } from "react-redux"
import { changeBg } from "./store.js"

function App() {
    let dispatch = useDispatch();
    let a = useSelector((state) => state.bg )

    return (
        <div>
            <Button
                variant={a == "light" ? "dark" : "light"}
                onClick={() => {
                  let changeColor = a == "light" ? "dark" : "light"
                  dispatch(changeBg(changeColor))
                  localStorage.setItem("mode", changeColor)
                  }}  
            >
                {a == "light" ? "Dark" : "Light"}
            </Button>
        </div>
    )
}

styled-components

이미 눈치챘겠지만 플리맨은 디자이너가 없고 대부분 부트스트랩으로 만들어졌다. 사실 그래서 1시간뿐이 안걸린거다. 서비스가 복잡하고 색조합이 알록달록했으면 몇 일이 걸렸을지 모른다. 부트스트랩 이외의 컴포넌트는 아래 코드처럼 styled-components로 작업했다.

import styled from 'styled-components'


let H5 = styled.h5`
  color : ${ props => props.c };
`;

let P = styled.p`
  color : ${ props => props.c };
`;
<H5 c={a == "light" ? "dark":"white"}>플리맨</H5>

마무리

다크모드를 뭘로 만들었고 어떻게 만들었는지 알아보았다. 디자인이 복잡하지 않은 서비스라면 같은 방법으로 쉽게 다크모드를 구현할 수 있을 것이다. 더 좋은 방법이 있으면 댓글에 공유해줬으면 좋겠다.
요즘은 플리맨 트래픽이 늘지않아 고민이 많다. 어떻게 하면 트래픽을 효율적으로 늘릴수 있는지 조언도 대환영이다. (댓글을 오매불망 기다리고 있습니다)
다음번에도 생각이 정리되는대로 좋은 내용 가지고 돌아오겠다!

profile
Deepveloper, deeplol.gg, fleaman.shop

3개의 댓글

comment-user-thumbnail
2022년 12월 22일

Thanks to this article I can learn more. Expand my knowledge and abilities. Actually the article is very real.

https://www.mybalancenow.tips/

1개의 답글
comment-user-thumbnail
2022년 12월 23일

댓글

답글 달기