본문 바로가기
Frontend/React

[React] React Component Styling

by 디스코비스킷 2023. 8. 25.
반응형

React Component Styling

01. Style Loaders

style-loader, css-loader가 .css나 .scss를 컴파일링해서 빌드함

eject 설정

웹팩설정을 꺼내서 설정을 하기위해 npm run eject 한번해야한다.

커밋하기

eject는 아직 git에 커밋되지 않은 변화가 있다면 진행되지 않아서 먼저 커밋해줘야한다.

git add .
git commit -m "commit before eject

config/webpack.config.js 설정

config/webpack.config.js 열어본다.

임포트 절대경로 설정방법

기존에 상대경로 임포트를 절대경로로 사용하기위해 설정할 수 있는 방법이다.
@import '../../../styles/utils';
@import utiles.scss;로 사용하기 위해
config/webpack.config.js에서 다음으로 수정한다.

{
    test: sassRegex, 
    exclude: sassModuleRegex,
    use: getStyleLoaders({
    importLoaders: 2,
    sourceMap: isEnvProduction && shouldUseSourceMap
    }).concat({ // 여기부터 추가설정
        loader: require.resolve('sass-loader'),
        options: {
            sassOptions: {
                includePath: [path.appSrc + '/styles']
            },
            sourceMap: isEnvProduction && shouldUseSourceMap,
          prependData: `@import 'utils';` // 이부분 추가시 매번 import하지 않아도된다.
        }        
    }),
    sideEffects: true
},

컴포넌트 스타일링 4가지 방법

  1. import './App.css'; CSS
  2. import styles from './App.module.css'; CSS Module
  3. import './App.scss'; SCSS
    import './App.sass'; SASS
  4. import styles from './App.module.scss';
    import styles from './App.module.sass'; SASS Module

네가지 종류에 대해서 알아볼거임!

02. CSS, SASS

네이밍규칙BEM 방법론 사용

css를 쓰면 React자체적으로 scoping이 되지는 않아 내부적인 체계가 필요하다.
BEM (block element modifier)방법론으로 네이밍 규칙을 정할 수 있음
BEM 방법론이란

sass설치

App.css 를 App.scss로 수정후 클래스를 중첩하여(SCSS문법은 패스) 수정해주면 컴파일에러가 뜬다.
SASS를 설치해주면 완료
npm i sass

03. CSS module, SASS module

module이란?

모듈방식은 몰까?
css파일과 scss파일을 임포트시 전역적으로 적용되어 스코프가 오염되는 문제가 있다.

그런 단점을 피하고자 웹팩을 이용해 모듈을 임포트할때 오염되지않게 추가할 수 있다.
.module.css를 임포트하면 아래와 같이 원래 작성했던 이름과 다르게 변경된 클래스이름을 매칭하여 사용한다.

CSS Modules Stylesheet추가하기란?

CSS module 써보기

간단한 Button 컴포넌트를 만들어 CSS모듈을 써볼거임
Button.module.css

.button {
  background:#fff;
  border-radius: 3px;
  border: 1px solid red;
}

.loading {
  border: 2px solid gray;
  color: gray;
}

Button.jsx

import styles from "./Button.module.css";
import React from "react";

// const Button = (props) => <button className={styles["button"]} {...props} />
class Button extends React.Component {
  state = {
    loading: false,
  };

  render() {
    return <button 
      className={this.state.loading ? `${styles["button"]} ${styles["loading"]}` : styles["button"]} 
      onClick={this.startLoading} 
      {...this.props} 
    />;
  }

  startLoading = () => {
    this.setState({
      loading: true,
    });
    console.log(this.state.loading);
    setTimeout(() => {
      this.setState({
        loading: false,
      })
    }, 5000);
  }
}

export default Button;

classnames 라이브러리

클래스를 조건부로 사용할때 유용한 classnames라는 라이브러리를 써볼것이다.

설치 npm i classnames

사용법은 import후 className={classNames('one', 'two')}처럼 클래스에 사용한다.

classNames("apple", "banana") // apple banana
classNames({apple: true}, {banana: false}) // apple
classNames(null, false, "bar", undefined, 0 ,1, {apple :null}) // bar 1
classNames(classNames(styles["button"]), classNames(styles["loading"])) // 각 고유한 classname 나옴
이렇게 truthy한 값만 출력되니까 boolean prop을 받아서 조건부로 사용할 수 있다.

삼항연산자를 간단하게 만들어보자.

// 1. 기존
...
className={this.state.loading ? `${styles["button"]} ${styles["loading"]}` : styles["button"]}
...

// 2. bind하기(classnames에 내장되어 있는 bind함수 사용)
import classNames from "classnames/bind";
const cx = classNames.bind(styles); // 미리 styles에서 클래스를 받아오도록 설정

...
  render() {
    const {loading} = this.state;
    return <button 
      className={cx("button", {loading})}
      onClick={this.startLoading} 
      {...this.props} 
    />;
  }
...

classnames에 내장되어 있는 bind함수 사용하면 매번 styles.클래스이름으로 사용할 필요가 없어진다. 사전에 미리 styles에서 받아온 후 사용하게끔 설정해서 cx("클래스이름", "클래스이름2")로 사용가능하다.

sass 모듈도 css모듈과 같이 styles객체를 반환하기땜에 똑같이 쓸수 있음! 문법만 sass로 바꿔주면된다.

04. Styled Components (1)

리액트나 create-react-app이 아니라 별도의 라이브러리를 이용해서 편하게 관리할 수있다.
가장 대표적인 라이브러리인 Styled Components다. 두번째는 emotion이 잘 사용된다.

설치

npm i styled-components

사용법

src/components/StyledButton.jsx

import styled from 'styled-components';

const StyledButton = styled.button`
    background: blue;
`; // 이사이에 스타일 넣을수있음

export default StyledButton;

겹치지않게 관리해서 클래스를 넣어주고,
스타일을 자동으로 만들어주고,
클래스이름도 자동으로 만들어주고,
그것을 컴포넌트에 추가해주는것이
Styled Components의 역할!

문자열로 들어가서 오타같은것이 났을때 알기 어려워서 신중하게 작성해야한다.

05. Styled Components (2)

props전달받아 스타일 적용하기


StyledCButton.jsx

import styled, { css } from "styled-components";

const StyledButton = styled.button`
  background: transparent;
  border: 2px solid yellow;
  color: yellow;
  padding: 10px 20px;
  font-size: 24px;
  border-radius: 4px;
  margin: 10px;

  ${(props) =>
    props.primary &&
    css`
      background: yellow;
      color: #000;
    `}
`; // 이사이에 스타일 넣을수있음

export default StyledButton;

부모 컴포넌트에서 직접 커스텀해서 사용하기

App.js

import logo from './logo.svg';
import './App.css';
import StyledButton from "./components/StyledButton";
import styled, { css } from "styled-components";

const PrimaryStyledButton = styled(StyledButton)`
  background: yellow;
  color: #000;
`;

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <StyledButton>Click</StyledButton>
        <StyledButton primary>버튼</StyledButton>
        <PrimaryStyledButton>버튼</PrimaryStyledButton>
      </header>
    </div>
  );
}

export default App;

컴포넌트를 다른 element로 만들어 쓰기

<StyledButton as="a" href="/">버튼</StyledButton>
-> a태그로 StyledButton컴포넌트를 만듦

특정 컴포넌트를 만들어 스타일 땡겨(?)쓰기

...
const UppercaseButton = (props) => <button {...props} children={props.children.toUpperCase()} />;
 ...
<StyledButton as={UppercaseButton}>button</StyledButton>
...

일반적으로 이렇게 쓴다.

const MyButton = (props) => (
  <button {...props} children={`MyButton ${props.children}`} />
  // 원래 className={props.className}써야 먹혔는데 {...props}해도 됨
);
const StyledMyButton = styled(MyButton)`  
  background: transparent;
  color: ${(props) => props.color || "yellow"};
  border: 2px solid ${(props) => props.color || "yellow"};

  &:hover { // &을 안쓰면 공백이 들어가서 sass문법으로 써야 먹힘
    border: 2px solid red;
  }
  &::before {
    content: "@";
  }
`;

...
<StyledMyButton color="green">button</StyledMyButton>

전역으로는 스타일 적용

import styled, { createGlobalStyle } from "styled-components";

// 5. 전역적 사용시 다르게
const GlobalStyle = createGlobalStyle`
  button {
    color: pink;
  }
`;

<GlobalStyle /> // 최상위 바로 아래에 보통 두기

attribute 매번 주기 귀찮을때 일괄적용하기

StyledA.jsx

const StyledA = styled.a.attrs(props => ({
    target: "_BLANK"
}))`
    color: ${(props) => props.color};
`;

<StyledA href="http://www.google.com">구글</StyledA>

이렇게 사용하면 컴포넌트의 target attribute를 매번 쓰지 않아도된다.

06. React Shadow

HTML안에 원래 HTML에 영향을 주지 않는 별도의 HTML

웹 컴포넌트란?
웹 컴포넌트는 그 기능을 나머지 코드로부터 캡슐화하여 재사용 가능한 커스텀 엘리먼트를 생성하고 웹 앱에서 활용할 수 있도록 해주는 다양한 기술들의 모음

웹 컴포넌트

Shadow DOM
캡슐화된 "그림자" DOM 트리를 엘리먼트 — 메인 다큐먼트 DOM 으로부터 독립적으로 렌더링 되는 — 를 추가하고 연관된 기능을 제어하기 위한 JavaScript API 의 집합. 이 방법으로 엘리먼트의 기능을 프라이빗하게 유지할 수 있어, 다큐먼트의 다른 부분과의 충돌에 대한 걱정 없이 스크립트와 스타일을 작성할 수 있습니다.

react-shadow 설치

npm i react-shadow

컴포넌트를 shadowDOM으로 작업하여 다른곳에 있는 CSS영향 받지 않게 만들기

(스코프 격리 ? )

단점 : style이 보통 공통적으로 쓰는게 많아서 매번 써야함.
외부와 내부가 차단되어있기때문에 값을 받아쓰는데 제약이 있다.

그러므로...
css, styled component, shadowDOM 등 상황에 맞게 적절히 사용해야한다.

import logo from './logo.svg';
import root from 'react-shadow';

const styles = `
(App.css내용)
`;


function App() {
  return (
    <root.div> 
      {/* index의 css 영향 받지않게 */}
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
    <style type="text/css">{styles}</style>
    </root.div>
  );
}

export default App;

07. Ant Design

Ant Design 바로가기
이미디자인된것을 가지고 만들수 있다.

Ant Design 설치

npm i antd

기본적으로 만들어진 컴포넌트를 사용하면 만들어진 스타일도 적용됨
전역 css를 제공하고 있어서 임포트 적용해야함

import 'antd/dist/antd.css'; 해야된다고 하는데 하니까 에러나서 삭제해줬더니 정상작동됨. 버전 바뀌면서 수정되었나보다..



원래 이렇게 각 컴포넌트 css도 따로 가져와야 적용됐는데 이점을 개선하고자 자동화 하기위해 eject했어야했다.. (권장X 방법)

그런데 이제 하지 않아도 적용 잘 되는듯!!

Ant Design Icons

백오피스 등 만들때, 간단한 홈페이지 만들때 사용하기 좋음
npm install --save @ant-design/icons 따로 설치 필요함

컴포넌트 사용시 props를 제일 많이 중요시해야함
API 문서 잘 보기

그리드 시스템

그리드시스템도 제공하고있으니 사용하면 좋을것같다.

gutter는 16+8n의 정수
span의 총합은 24
offset은 띄어진 크기라 offset과 span의 합이 24가 되어야함

반응형

최근댓글

최근글

© Copyright 2023 jngmnj