6.0 Dark Mode 1,2
0) Intro
지금부터는 Recoil라이브러리를 이용하여 다크테마와 라이트테마를 설정하도록 해볼 것이다. 하지만, 라이브러리의 편리성을 확인하기 위해 라이브러리 없이 다크모드와 라이트모드를 적용하는 방식에 대해 알아보려고 한다.
Recoil에 대한 학습을 할 때 왜 라이트모드와 다크모드로 예시를 들까?
이렇게 모드를 전환하는 상황은 ‘Global’하게 무언가를 적용하는 상황이다. 첫 랜딩페이지에서 다크모드를 설정했다면, 이후에 넘어가게 될 다른 페이지들도 다크모드로 설정했다는 사실을 알아야 한다. 즉 전역적으로 적용하기 위한 상황을 구현해보려고 한다.
우선 DarkMode 1,2 에서는 다크모드를 어떻게 적요하는지를 확인해보자.
(1) Theme Provider
- 우선 index.tsx안에 있던 theme Provider를 App안으로 들여보내준다.
//index.tsx
<>
<ThemeProvider theme={}>
<button onClick={toggleDark}>Toggle Mode</button>
<GlobalStyle />
<Router />
</ThemeProvider>
</>
theme={}: theme변수 안에 전에 만들었던 lightTheme, darkTheme 인터페이스를 집어넣으면 전체 테마를 바꿀 수 있다.
(2) Button and State - with App.tsx
- State, EventListener
//App.tsx
const [isDark, setIsDark]=useState(true);
const toggleDark=()=>setIsDark((current)=>!current);
- isDark : 현재 다크모드 여부를 나타내는 변수
- toggleDark : 현재 isDark안에 있는 값을 반대로 변화시켜주는 함수. 버튼의 이벤트 리스너로 달아주어야 할 것 같다.
2. Button
<button onClick={toggleDark}>Toggle Mode</button>
3. App.tsx
<>
<ThemeProvider theme={}>
<button onClick={toggleDark}>Toggle Mode</button>
<GlobalStyle />
<Router />
</ThemeProvider>
</>
4. 문제 제기
그러나, 나는 App.tsx를 이용해서가 아니라, Coins페이지를 이용하여 theme에 대한 정보를 얻고 싶다.
지금 현재 파일의 구조는 다음과 같다.
App
│
├── Router.tsx
│ └── Coins.tsx
│ └── Coin.tsx
앱으로부터 theme에 접근이 가능하도록 하면 라우터에서만 그 정보에 접근이 가능하기 때문에 Coins까지만 접근이 가능한 상황이다.
그렇기 때문에 Router에 theme에 대한 정보를 부여해주고, 이 정보를 Coins와 Coin에서 사용할 수 있도록 코드를 수정해보려고 한다.
2) Adjustments
(1) Settings In Router
1. 목표
<Router toggleDark={toggleDark} />
라우터에 이렇게 toggle과 관련된 이벤트 리스너 함수를 보내려면 어떻게 해야 할까?
Router.tsx파일로 가서 조정을 해야 한다.
2. 수정
interface IRouterProps{
toggleDark: ()=>void;
}
function Router({toggleDark}:IRouterProps)
- toggleDark : 우리 지금까지 prop을 받으려면 그 형식을 interface의 형태로 적어서 할당을 해줬다.
이 때 함수를 받으려면 → 함수의 Call signiture를 interface에 적어줘야 한다.
- {toggleDark}:IRouterProps : prop으로 이벤트리스너 함수를 보낼 것임
(2) Handing over Info
Router에서 받은 정보를 한 번 더 Coins에 넘겨줘야 하고, 이 정보를 한 번 더 Coin에 넘겨주어야 한다.
<Coins toggleDark={toggleDark}/>
(동일한 과정을 Coins와 Coin에 적용해주면 되기 때문에 설명은 생략)
Theme에서 색을 받아서 적용하는 과정도 생략..
3) Problems
지금까지의 문제점은 무엇일까?
App(isDark, modifierFn)
->Router ->Coins (modifier)---for button's action
->Router ->Coin -> Chart(isDark)--- for Chart's Color
정보를 전달하는 경로가 너무 길다는 문제점이 발생한다. isDark변수와, toggleDark 함수가 App.tsx에서 발생했긴 하지만, 전역적으로 사용이 되어야 하는데, 루트를 계층적으로 이동을 해야 하기 때문에 너무 멀다.
(중간 단계에서 변수가 필요하지 않아도 전체 정보를 넘기고 넘기고 하는 방식에 문제가 있음)
4) Etc.. (extended situations)
이런식으로 전역적으로 정보가 이용되어야 하는 상황들은 모드전환 외에 어떤 것들이 있을까?
우선 로그인 여부에 대한 정보를 전달해야 하는 경우를 예로 들 수 있다.
우리는 웹에서 로그인 여부에 따라서 리스트의 일부만 보여지도록 하고, 나머지는 로그인을 해야 볼 수 있도록 설정할 수도 있다.
(생각해보면 회원 정보, 등급 등… 전역적으로 사용해야 할 정보들이 꽤나 된다.)
지금부터는 발생했던 문제를 염두에 두고, Recoil라이브러리를 활용하여 해결해보려고 한다.
6.2 Introduction to Recoil1,2
0) Intro + Problems
지금까지는 전역적인 변수가 없이 하청처럼 정보가 타고 내려오는 상황에 대한 문제점에 대해서 알아보았다. 지금부터는 recoil을 사용하여 전역변수를 선언하는 방식과, 이 변수를 수정하는 방식에 대해 알아보려고 한다.
구체적으로 지금까지 문제가 뭐였는지 정리해보자.
(1) Previous Problems
App(isDark, modifierFn)
->Router ->Coins (modifier)---for button's action
->Router ->Coin -> Chart(isDark)--- for Chart's Color
지금까지의 문제는, 말단에 있는 페이지에서 정보에 접근하기 위해서는, 말단까지 가기 위한 중간 단계의 함수들 모두에게 그 정보를 주어야 한다는 문제가 발생한다. 실제로 라우터나, Coin같은 페이지에서는 변수와 함수에 대한 정보가 필요하지 않음에도 하위 페이지로 내려가는 중간경로라는 이유만으로 전달이 되고 있다.

1) Solution + Recoil
지금부터는 Recoil을 이용하여 문제를 해결해보려고 한다.

리코일 기술문서를 살펴보면 저 그림이 포함되어 있는 영상이 하나 있다. 이처럼 Recoil은 전역적으로 ‘필요한 놈이 직접’ 값에 접근할 수 있는 형식을 갖고 있다.
2) Install, Utilizing
(1) Installing
npm install recoil
(2) Create Atom
import {atom} from "recoil";
export const isDarkAtom=atom({
key:"isDark",
default: false
})
isDarkAtom=atom({}): 아톰의 이름을 적어준 이후, atom함수 안에 객체 형태로 정보를 전달한다.key: atom을 생성할 때 필요한 첫 번째 요소다. 아톰의 이름을 적어준다.default: atom을 생성할 때 필요한 두 번째 필수요소다. 초기값을 적어준다.
이처럼 atom은 atom함수 안에 필수 요소인 key와 default값이 담긴 객체를 보내준다.
(3) Call
atom을 필요한 파일에 끌고와서 사용하는 방법에 대해 알아보자.
const isDark=useRecoilValue(isDarkAtom);
- useRecoilValue(name of the atom) : useRecoilValue 는 recoil의 값을 가져오는 함수다. 안에 atom의 이름 (=isDarkAtom, key값 아님)을 부여해준다.
즉 recoil에서 훅을 사용할 때는 항상 parameter자리에 변수명을 적어야한다.
(4) Modifying
atom의 값을 수정하는 방법에 대해 알아보자.
참고로 한 곳에서 수정하면 수정된 값으로 다른 곳에서도 적용이 된다.
전에 자주 사용했던 useState훅에서 modifier함수와 동일하게 사용해줄 수 있다.
const setDarkAtom=useSetRecoilState(isDarkAtom);
setDarkAtom(current=>!current);
또한 useState에서는 보통 변수랑, 그 변수를 조정하는 modifier함수 두 개를 동시에 꺼냈는데, recoil도 마찬가지로 시행할 수 있다.
const [isDark, setisDark] =useRecoilState(isDarkAtom);
하지만, setter가 필요 없는 경우나 value가 필요 없는 경우 일반적으로 그냥 하나씩만 받는 것이 효율적이다.
3) Sum
지금까지 전역적으로 사용되는 정보를, 일반적인 방식으로 접근했을 때의 어려움에 대해 알아보았다.
Recoil을 사용할 수밖에 없는 상황, 문제 제기와 이에 따른 해결책에 대해 개연성을 이해하고,
생성, 호출, 수정하는 방법까지 정리하며 복습하면 좋을 것 같다.
'프로그래밍 > React' 카테고리의 다른 글
| # React-Js Master Class #6-3 State Management (0) | 2025.02.28 |
|---|---|
| # React-Js Master Class #6-2 State Management (0) | 2025.02.24 |
| # React-Js Master Class #5-3 Crypto Tracker (0) | 2025.02.17 |
| # React-Js Master Class #5-2 Crypto Tracker (0) | 2025.02.11 |
| # React-Js Master Class #5-1 Crypto Tracker (0) | 2025.02.09 |