다크 모드 만들기에 아주 꽂혀버려서 상태 관리를 하게 되었다
Redux를 사용해서 전체 웹에서의 상태(display mode)를 관리하고자 한다
설치
npm install @reduxjs/toolkit
redux 폴더를 하나 만들고 action.js, reducers.jsx, store.jsx 파일을 만든다.
action.js
export const IS_DARK = false;
export function displayMode(mode) {
return {
type: IS_DARK,
mode,
};
}
reducers.jsx
// state
// false or true
import { IS_DARK } from "./actions";
const initialState = false;
export function setMode(previousState = initialState, action){
// 초기값 세팅
// if (previousState === undefined) {
// return [];
// }
if (action.type === IS_DARK) {
return action.mode;
}
return previousState;
}
store.jsx
import { configureStore } from '@reduxjs/toolkit';
import { setMode } from './reducers';
const display = configureStore({reducer: setMode});
export default display
이렇게 쓰고 index.js에서
import {displayMode } from "./redux/actions";
display.subscribe(() => {
console.log(display.getState());
});
display.dispatch(displayMode(true));
display.dispatch(displayMode(false));
결과를 확인할 수 있다. displayMode에 true를 넣어주는지, false를 넣어주는지에 따라 console에 이렇게 결과가 출력된다.
redux에서는 store는 단일 스토어이다.
store에서 각 component의 상태를 관리 하게 된다.
스토어를 만들기 위해서 액션을 정의하고, 액션을 사용하는 리듀서를 만들고 합쳐진 리듀서를 인자로 단일 스토어를 생성한다.
스토어를 사용하려면
import react-redux
import 후 connect 함수를 이용해서 컴포넌트에 연결하면 된다.
index.js에서
<React.StrictMode>
<App display={display}/>
</React.StrictMode>
App.js로 display(스토어)를 보내준다
App.js
const [state, setState] = useState(display.getState);
useEffect(() => {
const unsubscribe = display.subscribe(() => {
setState(display.getState());
});
return () => {
unsubscribe();
}
}, [display]);
const changeMode = () => {
display.dispatch(displayMode(!state));
}
여기서 changeMode는 원래 모드를 바꿔주던 전구 아이콘 버튼 안에 있던 함수이다. (onClick으로)
<p>{state.toString()}</p>
를 넣어서 확인해보자
true false로 잘 바뀌는 것을 볼 수 있다 -> 라고 썼는데 gif가 재생이 안되는군,,, 보이지 않지만 잘.. 바뀌었습니다😅
+upgrade ver(?) * HOOK으로 만들어서 전체 component에서 사용 가능하도록 하기
여기에선 createContext라는 것을 이용한다
contexts 폴더를 만들고 그 안에 ReduxContext.js 파일을 만들어 다음과 같이 적는다
import { createContext } from "react";
const ReduxContext = createContext();
export default ReduxContext;
그리고 hooks 폴더에 useReduxState.js와 useReduxDispatch.js를 만든다.
useReduxState.js에는 위에서 App.js에 추가했던 코드를 옮겨 온다
import { useEffect, useState, useContext } from "react";
import ReduxContext from "../contexts/ReduxContext";
export function useReduxState() {
const display = useContext(ReduxContext); //ReduxContext를 불러오는 코드가 추가 됐다
const [state, setState] = useState(display.getState);
useEffect(() => {
const unsubscribe = display.subscribe(() => {
setState(display.getState());
});
return () => {
unsubscribe();
};
}, [display]);
return state;
}
useReduxDispatch.js에서 store를 dispatch 할 수 있도록 코드를 작성한다.
import { useContext } from "react";
import ReduxContext from "../contexts/ReduxContext";
export function useReduxDispatch() {
const display = useContext(ReduxContext);
return display.dispatch;
}
이제 App.js에서
import { useReduxState } from "./hooks/useReduxState";
import { useReduxDispatch } from "./hooks/useReduxDispatch";
function App() {
const state = useReduxState();
const dispatch = useReduxDispatch();
~중략~
const changeMode = () => {
dispatch(displayMode(!state));
};
~중략~
}
이런 식으로 사용할 수 있다. 그리고 여기서 state는 다른 component 파일에서도
const state = useReduxState();
이렇게 불러와서 사용할 수 있다. => 이제 dark mode의 정보를 상태 관리를 통해 props로 직접 전달해주지 않아도 전체 component에서 사용할 수 있게 되었다!
2023.02.16 수정
ContextAPI를 사용하면 다크모드 정도는 redux를 사용하는 것보다 쉽게 구현할 수 있다
나의 버려진 티스토리 블로그에 포스팅 했었다
ContextAPI로 다크모드 만들기