[react-native] 스타일드 컴포넌트 styled-component

    반응형
    이 글은 <처음 배우는 리액트 네이티브(김범준, 한빛미디어)>를 읽고 이해한 바를 바탕으로 작성되었습니다.
    https://github.com/Alchemist85K/my-first-react-native
     

    GitHub - Alchemist85K/my-first-react-native: [한빛미디어] 처음 배우는 리액트 네이티브 소스 코드입니다.

    [한빛미디어] 처음 배우는 리액트 네이티브 소스 코드입니다. . Contribute to Alchemist85K/my-first-react-native development by creating an account on GitHub.

    github.com

    리액트 네이티브에서 컴포넌트에 스타일을 적용하는 방법은 css와 유사한 부분이 많았다.

    하지만,, 유사한 거지 똑같은 건 아니다.

    css에서는 하이픈(-)을 사용하지만 react native에서는 카멜 표기법으로 작성한다. 일부 값들은 css 속성과 이름이 같지만 타입이 다른 경우, 단위가 생략되는 경우도 있다. 이건, 비슷해서 더 헷갈린다!!

    이런 불편함을 해소하기위해 사용할 수 있는 것이 스타일드 컴포넌트(styled-components)이다.

    스타일드 컴포넌트는 자바스크립트 파일 안에 스타일을 작성하는 CSS-in-JS 라이브러리이며, 스타일이 적용된 컴포넌트이다.

     

    💡스타일드 컴포넌트 사용하기 

    스타일 컴포넌트를 사용하기 위해서는 각 프로젝트 파일안에서 아래 명령어를 이용하여 스타일드 컴포넌트를 설치해야한다.

    중요한건, 스타일드 컴포넌트를 사용하려면 프로젝트 각각 매번 설치해주어야한다!!!

    npm install styled-components

    ((

    사실 나는 이 스타일드 컴포넌트를 import하는데서부터 계속 오류가 났었다. 약 3주 동안 해결을 못했었다.

    이 styled-components를 설치하는 경로 문제 + expo SDK 버전 문제때문에 계속 오류가 났었다.

    + 에러 해결 방법

    https://eunbin00.tistory.com/32

     

    [react-native] styled-component를 import하는데 오류가 난다면?

    import styled from 'styled-components/native' ... 코드 잘 써놓고, 안드로이드 에뮬레이터에서 돌렸더니 저런 오류가 뜬다. terminal에서는 import 하는 부분에서 error가 난다고 뜬다. 그래서 우선, npm으로..

    eunbin00.tistory.com

    ))

     

    이렇게 설치를 해주면 스타일드 컴포넌트를 사용할 수 있다.

     

    예시코드는 다음과 같다.

    import styled from 'styled-components/native'
    const MyTextStyledComponent = styled.Text`
    	color: #fff;
    `;

    이렇게 styled.[컴포넌트 이름] 뒤에 백틱(`)을 사용하여 만든 문자열을 붙이고, 그 안에 스타일을 css로 작성해주면된다.

    이런 문법을 tagged template literal이라 한다고 한다. 

     

    💡스타일드 컴포넌트를 사용하는 이유

    앱을 만든다고 생각해보자.

    분명, 공통적인 스타일을 적용해야 하는 경우가 생길거고, 이 코드를 매번 작성하는 건 너무 비효율적인 일이다.

    중복되는 스타일을 재하용 가능한 코드로 분리해내는 상황에서 스타일드 컴포넌트에서는 css를 이용하여 재사용이 가능한 코드를 관리할 수 있다.

    import styled,  {css} from 'styled-components/native';
    
    const whiteText = css`
        color: #fff;
        font-size: 14px;
    `;
    
    const MyBoldTextComponent = styled.Text`
        ${whiteText}
        font-weight: 600
    `;
    
    const MyLightTextComponent = styled.Text`
        ${whiteText}
        font-weight: 200
    `;

    whiteText를 css를 이용해 스타일을 지정해놓고 다른 comonent에서 ${whiteText}로 재사용할 수 있다.

     

     

    또, 완성된 컴포넌트를 상속받아 이용하는 방법도 있다.

    import styled from 'styled-components/native';
    
    const StyledText = styled.Text`
        color: #000;
        font-size: 20px;
        margin: 10px;
        padding: 10px;
    `;
    
    const ErrorText = styled(StyledText)`
        font-weight: 600;
        color: red;
    `;

    이렇게 스타일드 컴포넌트로 이미 만들어 놓은 컴포넌트를 styled(상속받을 컴포넌트 이름)``;로 소괄호로 감싸주면 상속받아올 수 있다.

     

    💡스타일드 컴포넌트로 스타일 적용하기

    직접 스타일드 컴포넌트로 버튼 컴포넌트를 만들어보겠다.

    import React from 'react';
    import styled from 'styled-components/native';
    
    const ButtonContainer = styled.TouchableOpacity`
        background-color: #9b59b6;
        border-radius: 15px;
        padding: 15px 40px;
        margin: 10px 0px;
        justify-content: center;
    `;
    
    const Title = styled.Text`
        font-weight: 600;
        color: #fff;
    `;
    
    const Button = props => {
        return (
            <ButtonContainer>
                <Title>{props.title}</Title>
            </ButtonContainer>
        );
    };
    
    export default Button;
    
    /* src/components/Button.js */

    TouchableOpacity 컴포넌트와 Text 컴포넌트에 스타일드를 적용해서 ButtonContainer와 Title 컴포넌트를 만들었고, Button 컴포넌트에 넣어주었다.

     

    import React from 'react';
    import styled from 'styled-components/native';
    import Button from './components/Button';
    
    const Container = styled.View`
        flex: 1;
        background-color: #ffffff;
        align-items: center;
        justify-content: center;
    `;
    
    const App = () => {
        return (
            <Container>
                <Button title='Eunbin' />
                <Button title='React Native' />
            </Container>
        );
    };
    
    export default App;
    
    /* src/App.js */

    view 컴포넌트에 스타일드를 적용하여 Container 컴포넌트를 만들었고, App에 Container안에 Button 컴포넌트 2개를 props와 함께 넣어준다.

    💡props 사용하기

    스타일드 컴포넌트에서는 스타일을 작성하는 백틱(`)안에서 props에 접근할 수 있다는 장점을 이용해서 스나일을 작성하는 곳에서 조건에 따라 스타일을 변경할 수 있다.

    예를 들어, 버튼 컴포넌트에서 props로 전달되는 title값이 'Eunbin'인 경우, 배경색을 바꿔준다고 하면,

    import React from 'react';
    import styled from 'styled-components/native';
    
    const ButtonContainer = styled.TouchableOpacity`
        background-color: ${props =>
            props.title === 'Eunbin' ? '#3498db' : '#9b59b6'};
        border-radius: 15px;
        padding: 15px 40px;
        margin: 10px 0px;
        justify-content: center;
    `;
    
    const Title = styled.Text`
        font-weight: 600;
        color: #fff;
    `;
    
    const Button = props => {
        return (
            <ButtonContainer title={props.title}>
                <Title>{props.title}</Title>
            </ButtonContainer>
        );
    };
    
    export default Button;
    
    /* src/comonents/Button.js */

    이렇게 스타일 작성에서 직접 props에 접근하여 조건 지정이 가능하다!

     

    💡attrs 사용하기

    # 스타일드 컴포넌트를 사용하면 스타일을 지정하는 곳에서 컴포넌트의 속성을 지정하는 것도 가능하다.

    import React from 'react';
    import styled from 'styled-components/native';
    
    const StyledInput = styled.TextInput`
        width: 200px;
        height: 60px;
        margin: 5px;
        padding: 10px
        border-radius: 10px;
        border: 2px;
        border-color: #3498db;
        font-size: 24px;
    `;
    
    const Input = () => {
        return <StyledInput placeholder='Enter a text...' placeholderTextColor='#3498db' />
    }
    
    export default Input;
    import React from 'react';
    import styled from 'styled-components/native';
    import Button from './components/Button';
    import Input from './components/Input';
    
    const Container = styled.View`
        flex: 1;
        background-color: #ffffff;
        align-items: center;
        justify-content: center;
    `;
    
    const App = () => {
        return (
            <Container>
                <Button title='Eunbin' />
                <Button title='React Native' />
                <Input />
            </Container>
        );
    };
    
    export default App;

    스타일드로 만든 StyledIput 컴포넌트에 placeholder 속성과 placeholderTextColor 속성을 지정해주었다.

     

    # 속성을 설정할 때, 앞에서 본 것처럼 전달된 props에 접근할 수 있기 때문에 props의 값에 따라서 속성을 변경할 수도 있다.

    import React from 'react';
    import styled from 'styled-components/native';
    
    const StyledInput = styled.TextInput.attrs(props => ({
        placeholder: 'Enter a text...',
        placeholderTextColor: props.borderColor,
    }))`
        width: 200px;
        height: 60px;
        margin: 5px;
        padding: 10px
        border-radius: 10px;
        border: 2px;
        border-color: ${props => props.borderColor};
        font-size: 24px;
    `;
    
    const Input = props => {
        return <StyledInput borderColor={props.borderColor} />;
    }
    
    export default Input;
    
    /* src/components/Input.js */

    스타일 속성 지정에서 border-color를 props로 받아온 값으로 설정하도록 하고,

     

    import React from 'react';
    import styled from 'styled-components/native';
    import Button from './components/Button';
    import Input from './components/Input';
    
    const Container = styled.View`
        flex: 1;
        background-color: #ffffff;
        align-items: center;
        justify-content: center;
    `;
    
    const App = () => {
        return (
            <Container>
                <Button title='Eunbin' />
                <Button title='React Native' />
                <Input borderColor='#3498db'/>
                <Input borderColor='#9859b6' />
            </Container>
        );
    };
    
    export default App;
    
    /* App.js */

    Input 컴포넌트에서 prop로 borderColor에 값을 지정하여 넘겨준다!

    짠 이뿌네

    이렇게 attrs를 이용하면 스타일을 설정하는 곳에서 props의 값에 따라 컴포넌트의 속성을 다르게 적용할 수도 있고, 항상 일정하게 적용할 수도 있다.

     

    💡ThemeProvider

    스타일드 컴포넌트의 ThemeProvider는 Context API를 활용해 애플리케이션 전체에서 스타일드 컴포넌트를 이용할 때 미리 정의한 값들을 사용할 수 있도록 props로 전달한다.

     

    #미리 정의한 색 사용하기

    export const theme = {
        purple: '#9b59b6',
        blue: '#3498db',
    };
    
    /* src/theme.js */

    theme.js 파일을 따로 만들어서, 사용할 색을 puple, blue로 미리정의해둔다.

     

    import React from 'react';
    import styled from 'styled-components/native';
    
    const ButtonContainer = styled.TouchableOpacity`
        background-color: ${props =>
            props.title === 'Eunbin' ? props.theme.blue : props.theme.purple};
        border-radius: 15px;
        padding: 15px 40px;
        margin: 10px 0px;
        justify-content: center;
    `;
    
    const Title = styled.Text`
        font-weight: 600;
        color: #fff;
    `;
    
    const Button = props => {
        return (
            <ButtonContainer title={props.title}>
                <Title>{props.title}</Title>
            </ButtonContainer>
        );
    };
    
    export default Button;
    
    /* src/compoenents/Button.js */

    Button 컴포넌트에서 스타일을 정의할 때, props로 전달되는 theme을 이용하도록 하였다. 

     

    import React from 'react';
    import styled, {ThemeProvider} from 'styled-components/native';
    import Button from './components/Button';
    import Input from './components/Input';
    import {theme} from './theme'
    
    const Container = styled.View`
        flex: 1;
        background-color: #ffffff;
        align-items: center;
        justify-content: center;
    `;
    
    const App = () => {
        return (
            <ThemeProvider theme = {theme}>
                <Container>
                    <Button title='Eunbin' />
                    <Button title='React Native' />
                    <Input borderColor='#3498db'/>
                    <Input borderColor='#9b59b6' />
                </Container>
            </ThemeProvider>
            
        );
    };
    
    export default App;
    
    /* App.js */

    themeprovider와 만들어둔 theme.js를 불러와서 App Component 안에서 Themeprovider로 묶어준다.

    ((저기 input 컴포넌트에서도 theme.blue, theme.purple을 사용해보고 싶은데, 어떻게 사용해야하는지 모르겠다...,,,ㅜ_ㅜ))

     

    이렇게 ThemeProvider를 사용해서 theme을 지정하면 하위 컴포넌트에서 theme의 미리 정의된 색을 모두 사용할 수 있다. 변수명도 의미있게 사용할 수 있고, 색의 관리와 사용 유지보수도 훨씬 효율적일 수 있다.

     

    +) Theme을 두 개의 색을 정의해두고 사용자에 선택에 따라 Theme을 제공할 수도 있다. 우리가 쉽게 접할 수 있는 light Theme과 dart Theme을 사용하는 방식이 이런 식이다!

    export const lightTheme = {
        background: '#ffffff',
        text: '#ffffff',
        purple: '#9b59b6',
        blue: '#3498db',
    };
    
    export const darkThme = {
        background: '#34495e',
        text: '#34495e',
        purple: '#9b59b6',
        blue: '#3498db',
    };
    
    /* src/theme.js */

    우선, theme.js 파일에 lightTheme과 darkTheme에서 사용할 색을 정의한다.

     

    import React, {useState} from 'react';
    import {Switch} from 'react-native';
    import styled, {ThemeProvider} from 'styled-components/native';
    import Button from './components/Button';
    import Input from './components/Input';
    import {lightTheme, darkTheme} from './theme'
    
    const Container = styled.View`
        flex: 1;
        background-color: ${props => props.theme.background};
        align-items: center;
        justify-content: center;
    `;
    
    const App = () => {
        const [isDark, setIsDark] = useState(false);
        const _toggleSwitch = () => setIsDark(!isDark);
    
        return (
            <ThemeProvider theme={isDark ? darkTheme : lightTheme} >
                <Container>
                    <Switch value={isDark} onValueChange={_toggleSwitch} />
                    <Button title='Eunbin' />
                    <Button title='React Native' />
                    <Input borderColor='#3498db' />
                    <Input borderColor='#9b59b6' />
                </Container>
            </ThemeProvider>
            
        );
    };
    
    export default App;
    
    /* App.js */

    useState로 테마의 상태를 관리할 isDark와 상태를 변경할 setIsDark 함수를 만들고

    Switch 컴포넌트를 활용해서 isDark의 상태를 변경할 수 있게 하였다.

    import React from 'react';
    import styled from 'styled-components/native';
    
    const ButtonContainer = styled.TouchableOpacity`
        background-color: ${props =>
            props.title === 'Eunbin' ? props.theme.blue : props.theme.purple};
        border-radius: 15px;
        padding: 15px 40px;
        margin: 10px 0px;
        justify-content: center;
    `;
    
    const Title = styled.Text`
        font-weight: 600;
        color: #fff;
        color: ${props => props.theme.text};
    `;
    
    const Button = props => {
        return (
            <ButtonContainer title={props.title}>
                <Title>{props.title}</Title>
            </ButtonContainer>
        );
    };
    
    export default Button;
    
    /* src/component/Button.js */

    버튼의 title 색깔도 theme의 text props로 받아오도록 만든다.

     

     

    반응형

    댓글