styled-components

2022-11-28 hit count image

react-native 스타일링을 위해 styled-components 라이브러리를 활용하는 방법에 대해 알아보자.

react-native 프로젝트 생성

TypeScript를 적용한 프로젝트에서 진행합니다. RN에 TypeScript를 적용하는 방법은 이전 블로그를 참고하세요.

styled-components 라이브러리 설치

styled-components 라이브러리와 TypeScript 연동을 위한 라이브러리를 설치합니다.

npm install --save styled-components
npm install --save-dev babel-plugin-styled-components @types/styled-components-react-native
  • styled-components: styled-components 라이브러리입니다.
  • @types/styled-components-react-native: TypeScript에 필요한 styled-components의 타입입니다.
  • babel-plugin-styled-components: 필수는 아니지만 디버깅시 class명을 확인하기 쉽게 만들어 줍니다. babel.config.js에 아래와 같이 설정해 줍니다.
module.exports = {
  ...
  plugins: ['babel-plugin-styled-components'],
};

TypeScript가 styled-componets의 타입을 인식할 수 있도록 하기 위해, tsconfig.json 파일을 열고 다음과 같이 수정합니다.

{
  ...
  "compilerOptions": {
    ...
    "types": ["@types/styled-components-react-native"]
  },
}

ERESOLVE unable to resolve dependency tree

styled-components를 설치할 때, 다음과 같은 에러가 발생할 때가 있습니다.

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree

이 때는 React Native 프로젝트 폴더에 .npmrc 파일을 생성하고 다음과 같이 수정합니다.

legacy-peer-deps=true

그리고 다시 styled-components를 설치하면 문제없이 설치되는 것을 확인할 수 있습니다.

사용법

styled-components는 전체 스타일을 관리하기 위한 theme 기능을 제공합니다. theme을 사용하는 방법과 기본적인 사용법을 알아봅니다.

Class Components에서 기본 사용법

  • 기본 스타일 적용
// src/App.tsx
...
import styled from 'styled-components/native';
...
const Container = styled.View`
  flex: 1;
  justify-content: center;
  align-items: center;
  background-color: #f5fcff;
`;
const MainText = styled.Text`
  font-size: 20px;
  text-align: center;
  margin: 10px;
  color: red;
`;
...
interface Props {}
interface State {}
export default class App extends React.Component<Props, State> {
  render() {
    return (
      <Container>
        <MainText>Hello world</MainText>
      </Container>
    );
  }
}
  • props를 이용해 동적으로 스타일 적용
// src/App.tsx
...
import styled from 'styled-components/native';
...

interface IContainerProps {
  background: string;
}

const Container = styled.View`
  flex: 1;
  justify-content: center;
  align-items: center;
  background-color: ${(props:IContainerProps) => props.background ? props.background : 'white'};
`;
const MainText = styled.Text`
  font-size: 20px;
  text-align: center;
  margin: 10px;
  color: red;
`;
...
interface Props {}
interface State {}
export default class App extends React.Component<Props, State> {
  render() {
    return (
      <Container background="red">
        <MainText>Hello world</MainText>
      </Container>
    );
  }
}

Class Components에서 Theme 사용법

공식 사이트에는 TypeScript를 이용하여 theme을 사용하는 방법이 자세히 나와있습니다.

공식 사이트와 예제 사이트를 참고하면 styled-components를 사용하기 위해서는 상대 경로로 지정해야하는 문제가 있다.

그래서 우리는 공식 사이트 방식이 아닌 “props를 이용해 동적으로 스타일 적용” 방법을 응용해서 사용합니다.

  • src/@types/index.d.ts 파일
// src/@types/index.d.ts
interface ITheme {
  color: {
    white: string;
    black: string;
  };
  fonts: {
    normal: string;
  };
}
  • src/Theme.tsx 파일
// src/Theme.tsx
export default {
  color: {
    white: '#FFFFFF',
    black: '#000000',
  },
  fonts: {
    normal: '14px',
  },
};
  • src/App.tsx 파일
...
// src/App.tsx
import { ThemeProvider } from 'styled-components';
import styled from 'styled-components/native';
import Theme from './Theme';
...

interface IContainerPorps {
  theme?: ITheme;
}

const Container = styled.View`
  flex: 1;
  justify-content: center;
  align-items: center;
  background-color: ${(props:IContainerProps) => props.theme && props.theme.color.black};
`;
const MainText = styled.Text`
  font-size: 20px;
  text-align: center;
  margin: 10px;
  color: red;
`;
...
interface Props {}
interface State {}
export default class App extends React.Component<Props, State> {
  render() {
    return (
      <ThemeProvider theme={Theme}>
        <Container>
          <MainText>Hello world</MainText>
        </Container>
      </ThemeProvider>
    );
  }
}

Function Components에서 기본 사용법

import React from 'react';
import styled from 'styled-components/native';

const Container = styled.View`
  flex: 1;
  justify-content: center;
  align-items: center;
  background-color: #f5fcff;
`;
const MainText = styled.Text`
  font-size: 20px;
  text-align: center;
  margin: 10px;
  color: red;
`;

interface Props {}
const App = ({}: Props) => {
  return (
    <Container>
      <MainText>Hello world</MainText>
    </Container>
  );
};

export default App;

Function Components에서 Theme 사용법

import React from 'react';
import styled from 'styled-components/native';
import {ThemeProvider} from 'styled-components';
import Theme from './Theme';

interface StyledProps {
  theme: ITheme;
}
const Container = styled.View`
  flex: 1;
  justify-content: center;
  align-items: center;
  background-color: ${(props: StyledProps) =>
    props.theme && props.theme.color.black};
`;
const MainText = styled.Text`
  font-size: 20;
  text-align: center;
  margin: 10px;
  color: red;
`;

interface Props {}
const App = ({}: Props) => {
  return (
    <ThemeProvider theme={Theme}>
      <Container>
        <MainText>Hello world</MainText>
      </Container>
    </ThemeProvider>
  );
};

export default App;

참고

제 블로그가 도움이 되셨나요? 하단의 댓글을 달아주시면 저에게 큰 힘이 됩니다!

앱 홍보

책 홍보

블로그를 운영하면서 좋은 기회가 생겨 책을 출판하게 되었습니다.

아래 링크를 통해 제가 쓴 책을 구매하실 수 있습니다.
많은 분들에게 도움이 되면 좋겠네요.

스무디 한 잔 마시며 끝내는 React Native, 비제이퍼블릭
스무디 한 잔 마시며 끝내는 리액트 + TDD, 비제이퍼블릭
[심통]현장에서 바로 써먹는 리액트 with 타입스크립트 : 리액트와 스토리북으로 배우는 컴포넌트 주도 개발, 심통
Posts