[기능 구현] Recoil을 사용하여 다크모드 기능 구현하기

유병현·2023년 6월 16일
0
post-thumbnail

다크모드란?

요즘 모바일 앱이나 사이트를 이용하다 보면 간간이 다크모드라는 기능을 들어봤을 것이다. 다크모드란 무엇일까? 간단히 말하자면 원래 사용하는 배경화면 대신 어두운 배경화면을 제공하는 기능이다.

그렇다면 이 기능의 장점은 무엇일까?

첫째, 화면을 볼 때 눈의 피로를 줄여줄 수 있다. 화면의 밝기는 방출되는 빛의 양에 비례한다. 어두운 화면일수록 방출되는 빛의 양이 줄어들 것이고, 몇 시간 동안 화면을 봐야하는 사람들에게는 다크모드 기능을 사용함으로써 눈의 피로를 줄여줄 수 있다.

둘째, 전력의 사용량을 줄여준다. 위의 장점과 비슷한 맥락이다. 당연히 빛을 방출하는 양을 줄여주니 자연스레 전력의 사용량을 줄여줄 수 있다. 예를 들어, 휴대폰 같은 경우 밝기를 최고로 한 상태와 밝기를 최소로 줄인 상태를 비교했을 때 당연히 밝기를 최소로 줄인 휴대폰의 배터리가 오래가는 것을 알 수 있다.

결론

그래서 이번 소개는 상태 관리 라이브러리인 Recoil을 이용하여 다크모드 기능을 구현하는 것에 대해 글을 써보고자 한다. 그렇다면 먼저 Recoil에 대해서도 알아볼 필요가 있다.

Recoil

사용한 이유?

가장 먼저 Recoil을 사용한 이유는 간단하다. 먼저 전역 상태 관리를 사용하는 이유 중 하나는 props drilling으로 인해 생길 수 있는 문제를 방지하기 위해서다. 나도 물론 이와 같은 이유로 전역 상태 관리를 사용하기도 했다. 컴포넌트의 depth 깊어질수록 prop이 하위 컴포넌트로 전달되는 깊이가 깊어지는데 이는 prop이 어디서 왔는지 찾기 힘들고, 나중에 유지보수가 힘들다는 단점이 있다.

그것을 방지하기 위해 사용을 하였는데 그렇다면 React에서 제공하는 Context 를 사용하여 데이터를 전달하면 되는데 나는 왜 Recoil 을 선택하였을까.

  1. 가장 먼저 Context API의 경우, Provider로 감싼 자식 컴포넌트 안에서 Context를 활용한 상태값에 변경이 일어날 경우 모든 컴포넌트가 재 렌더링된다는 단점이 존재했다. 이런 경우 성능에 문제가 생길 수 있고, 그래서 Context API를 사용하여 상태 관리를 할 때는 정적인 상태에 관해 사용하는 것이 좋다.

그렇다면 Recoil은?

  1. Recoil의 경우, RecoilRoot로 감싼 자식 컴포넌트 중에 Recoil을 통해 상태 값이 변경되는 해당 컴포넌트만 재 렌더링이 되기 때문에 Context API의 단점을 보완할 수 있다. 이것이 내가 Recoil을 선택한 이유이다.

다크모드 기능 구현하기

atom.tsx

import { atom } from 'recoil';

export const mode = atom<boolean>({
  key: 'mode',
  default: false,
});
App.tsx

import { RecoilRoot } from 'recoil';

/* 
	먼저 Recoil을 사용하기 위해서는
    Root Component에서 하위 Component를 <RecoilRoot></RecoilRoot>로 감싸줘야한다.
    
    이는 Context API와 사용법이 비슷하며 감싼 컴포넌트에 Context를 제공하겠다는 뜻이다.
*/

export const App = () => {
	return (
    	<RecoilRoot>
			<Nav />
    	</RecoilRoot>
  );
}
Nav.tsx

import { useRecoilState } from 'recoil';
import mode from './atom.tsx';

export const Nav = () => {
	/* 
    	Recoil의 값을 사용하여 값을 변경할 때는 useRecoilState를 사용한다.
        
        이는 우리가 흔히 사용하던 useState와 비슷하다.
    */
    
	const [mode, setMode] = useRecoilState<boolean>(mode);
	
    /* 다크모드 Handler */
    const handleClickButton = () => {
    	/* 상태 값 변경 */
        setMode(!mode)
    }
	
	return (
    	<div>
        	<button onClick={handleClickButton}>다크모드</button>
        </div>
    );
}

이로써 준비는 끝이 났다. 이제 해당 mode 값을 이용하여 다크모드 기능을 구현해주면 될 것 같다. 나는 구현할 때 styled-component를 사용하여 해당 영역에 style을 주었다.

Nav.tsx

import styled from 'styled-components';
import { useRecoilState } from 'recoil';
import mode from './atom.tsx';

export const Nav = () => {
	const [mode, setMode] = useRecoilState<boolean>(mode);
	
    const handleClickButton = () => {
        setMode(!mode)
    }
	
	return (
    	<Layout darkmode={mode}>
        	<button onClick={handleClickButton}>다크모드</button>
        </Layout>
    );
}

const Layout = styled.div<{ darkmode:boolean }>`
	/*
    	다크모드 기능이 실행되었을 경우, 배경 검정색 && 색깔 흰색
        Default일 경우, 배경 흰색 && 색깔 검정색
    */

	background-color: ${prop => prop.darkmode ? 'black' : 'white'};
    color: ${prop => prop.darkmode ? 'white' : 'black'};
`

참고한 사이트

0개의 댓글