오티스의개발일기

[REACT-NATIVE] Redux Toolkit 과 Styled Components를 사용하여 자동 다크모드 라이트모드 구현하기 본문

개발/react-native

[REACT-NATIVE] Redux Toolkit 과 Styled Components를 사용하여 자동 다크모드 라이트모드 구현하기

안되면 될때까지.. 2022. 12. 23. 16:38
728x90

 

 

 

 

오늘은 styled components를 사용하여 자동 다크모드와 라이트모드를 구현할것이다.

 

 

 

#styled components 를 사용해야하는 이유

 

일단 사용방법은 그리 편하지는 않다

예를들어 style에 대한 코드를 작성할때

StyleSheet 를 사용할경우 어시스턴트가 잘되어있어 f 만처도 font-weight가 나오고

p 만 처도 padding이 나온다

본인은 주가 css 개발이 아니므로 나같은 사람한테는 매우 귀찮은 작업이다.

일단 인텔리제이와 vs코드에서 style components 를 사용했을시 어시스턴트가 안되는걸 확인했다.

 

그럼에도 불구하고 사용해야하는 이유는

 

바로 트랜드한 다크모드와 라이트 모드이다.

 

기본적으로 react는 기본 js처럼 css파일을 따로 만들고 공통적으로 쓸수가 없기때문에

매 component 마다 style을 따로 적어줘야하고

거기에 다크모드와 라이트 모드를 사용하면다면 

매번 usecolorscheme 를 사용해서

어떤모드인지 판별후 그에맞는 스타일을 적용해야하기떄문에

혼자 작업하는 나같은 개발자는 이런것들을 꼭 찾아야한다.

 

자 이제 시작해보자

 

 

 

# 이 프로잭트의 원리

 

대략적인 원리는 이렇다

일단 redux toolkit으로 상태관리를 해주고

다크모드와 라이트 모드가 적혀저있는 js 파일을 생성한다.

그리고 처음 app에 들어왓을때 usecolorscheme 로 모드를 확인하고

styled-components 에서 제공해주는 ProviderTheme 를 사용하여

자식컴포넌트에다 뿌려준다

그리고 매 컨포넌트에서 useSelect를 사용하여 모드확인후 style을 적용시켜준다.

 


 

그전 포스팅에서 Redux Toolkit에 대해 설명하였다

Redux Toolkit 대해 모르는 사람은 이해하는데 힘들수있으니

참고바란다

 

2022.12.21 - [개발/react-native] - [REDUX] Redux Toolkit 사용해보기 + 로그인 버튼 Client 단부터 reducer 까지 -git첨부-

 

[REDUX] Redux Toolkit 사용해보기 + 로그인 버튼 Client 단부터 reducer 까지 -git첨부-

< 이전글 2022.12.21 - [개발/react-native] - [REACT NATIVE] Redux-Saga 프로젝트 시작하기 [REACT NATIVE] Redux-Saga 프로젝트 시작하기 < 이전글 2022.12.20 - [개발/react-native] - [REACT NATIVE] IMMER 사용하기 + REDUX 추가설명

otis.tistory.com

 


# 0. 폴더 구조

# 1. 모듈 다운로드

styled-components 는 yarn으로 받자
이유는 모르겠지만 충돌로인해 npm으로 다운로드가 불가능하다.

yarn add styled-components


npm install redux
npm install react-redux
npm install @reduxjs/toolkit
npm install redux-devtools-extension

	or
    
    
yarn add redux
yarn add react-redux
yarn add @reduxjs/toolkit
yarn add redux-devtools-extension

 

# 2. store.js 생성

 

// store.js
import {configureStore} from '@reduxjs/toolkit'


import rootSlicer from "./src/slicers/rootSlicer"; // 리듀서 모음집이라 생각하면된다
// 리듀서를 하나하나 만들어서 이곳에 생성해도 되지만 가독성을 위해 하나의 리듀서안에 여러가지를 넣고 사용한다.


// 위에서 만든 reducer를 스토어 만들때 넣어줍니다
let store = configureStore({
    reducer: rootSlicer,
    devTools: process.env.NODE_ENV !== 'production', // 프로덕션 모드일때는 devTools 차단
                                    // 추가적으로 원하는 커스텀 미들웨어를 배열형식으로 추가시키면된다.
});

export default store;

 

 

 

# 3 rootSlicer.js ( = rootReducer) 생성

// src/slicers/rootSlicer

// 여러 reducer를 사용하는 경우 reducer를 하나로 묶어주는 메소드
// store에 저장되는 리듀서는 오직 1개이지만 그 1개에 여러개의 리듀서가 들어갈수있음
import { combineReducers } from "redux";
import themeSlice from "./themeSlicer.js"; // 만든 리듀서'
// 이름도 알기쉽게 바꿔준다.  userReducer => userSlice

const rootReducer = combineReducers({
    themeSlicer : themeSlice.reducer,
    // redux toolkit
    // userReducer : userReducer =>  userSlice : userSlice.reducer(),
});

export default rootReducer;

그전에는 rootReducer 라는 말을 썼는데 toolkit을 쓰고 난후로부터 slicer로 통일시키기로 하였다.

참고바란다.

 

 

 

 

# 4.Theme.js (다크모드 라이트모드 스타일) 생성

export const darkTheme = {
    mode: 'dark',
    backgroundColor: '#212121',
    Textcolor: '#ffffff',
    buttonColor: '#23a8d9',
    buttonTextColor: '#ffffff',
    barStyle: 'light-content'
}


export const lightTheme = {
    mode: 'light',
    backgroundColor: '#ffffff',
    Textcolor: '#212121',
    buttonColor: '#8022d9',
    buttonTextColor: '#ffffff',
    barStyle: 'default'
}

 

이제 이곳에 원하는 색깔을 지정해놓으면 다른부분에서도 바뀔것이다.

 

 

 

 

# 5.themeSlicer.js 생성

// src/slicers/themeSlicer.js
import { createSlice } from '@reduxjs/toolkit' // toolkit 추가된 임포트
import {lightTheme} from '../../Theme'
const initialState = {
    theme: lightTheme
}

const themeSlice = createSlice({
    name: 'userSlice',
    initialState: initialState,
    reducers: { // 동기적인  액션을 넣는다.   내부적인 액션
        changeTheme (state, action) {
            state.theme = action.payload
        },
    },
});
export default themeSlice;

디폴트는 위에있는 Theme.js의 라이트 모드로 지정해놨다,

이곳에서 상태가 바뀔것인데.

payload에 Theme.js안에있는 다크모드 혹은 라이트모드가 매게변수로 들어올 예정이다.

 

 

 

# 6.App.js provider 생성

 

// App.js

import {Provider} from "react-redux";
import store from "./store";
import HomeScreen from './src/screens/HomeScreen';

export default function App() {
  
  return (
    <Provider store={store}>
      <HomeScreen/>
    </Provider>
  );
}

redux를 사용하려면 최상단 부모에다 <Provider> 를 감싸줘야한다.

 

 

 

# 7.HomeScreen.js 생성  <<< 메인

import React from "react";
import styled, { ThemeProvider } from "styled-components/native";
import { useDispatch, useSelector } from "react-redux"; // userDispatch = 데이터 변경시 사용 // useSelector = 데이터 가져올때 사용
import { darkTheme, lightTheme } from "../../Theme";
import themeSlicer from "../slicers/themeSlicer";
const HomeScreen = ({}) => {
  const theme = useSelector((state) => state.themeSlicer.theme);
  const dispatch = useDispatch();
  return (
    <ThemeProvider theme={theme}>
      <Container>
        <TextContainer>
          <Text>모드 : {theme.mode}</Text>
        </TextContainer>
        {theme.mode === "light" ? (
          <Button
            onPress={() => dispatch(themeSlicer.actions.changeTheme(darkTheme))}
          >
            <ButtonText>다크모드로 전환</ButtonText>
          </Button>
        ) : (
          <Button
            onPress={() =>
              dispatch(themeSlicer.actions.changeTheme(lightTheme))
            }
          >
            <ButtonText>라이트 모드로 전환</ButtonText>
          </Button>
        )}
      </Container>
    </ThemeProvider>
  );
};

const Container = styled.View`
  flex: 1;
  align-items: center;
  justify-content: center;
  background-color: ${props => props.theme.backgroundColor};
`;

const TextContainer = styled.View`
  border: 1px solid ${props => props.theme.Textcolor};
  padding: 16px;
  border-radius: 6px;
`;

const Text = styled.Text`
  color: ${props => props.theme.Textcolor};
  font-size: 24px;
  font-weight: 600;
`;

const Button = styled.TouchableOpacity`
    margin: 32px;
    background-color: ${props => props.theme.buttonColor};
    padding: 16px 32px;
    border-radius: 6px;
`;

const ButtonText = styled.Text`
  color: ${props => props.theme.buttonTextColor};
  font-size: 15px;
  font-weight: 500;
`;

export default HomeScreen;

 

상단에 임포트를 주목하자

import styled, { ThemeProvider } from "styled-components";  (x)

import styled, { ThemeProvider } from "styled-components/native";  (o)

리엑트 네이티브에서 styled components를 사용하려면 하위폴더 native를 사용해야 오류가 나지않는다.

이것때문에 1시간정도 삽질하였다....

 

 

그리고 또한 하단에 style component들을 봐보자

이제는 styleSheet를 사용하지않고

말그대로 style을 컴포넌트처럼 사용하는것이다.

 

그리고 최상단에 ThemeProvider를 감싸주고 그안에는 내가 사용할 태마를 넣어주면

그때부터는 자신이 만든 style 컴포넌츠안에서 객체형식으로 꺼내서 쓸수있다.

 

다만  ${props => props.theme.Textcolor} 이런형식으로 사용해야한다.

 

 

 

실제 구동한 모습이다.

 

 

실제 구동한 모습

 

 

여기까지 styled components 와 redux toolkit을 사용해 다크모드구현을 마치도록 하겠다.

 

 

728x90
Comments