본문 바로가기
Study/Udemy-React-완벽 가이드

6. 리액트 컴포넌트 스타일링 (feat. 유데미 React 완벽 가이드)

by NFAP0221S 2022. 5. 30.

https://www.udemy.com/course/best-react/

 

【한글자막】 React 완벽 가이드 with Redux, Next.js, TypeScript

Javascript부터 웹 어플리케이션 배포까지, React와 프론트엔드 최신 기술을 가장 쉽고 확실하게 배우는 법

www.udemy.com

이 게시물은 유데미 React 완벽 가이드 강의를 보고 메모를 남기는 게시물 입니다.


동적 인라인 스타일링

예전 글에서 JSX 태그에 style을 추가하여 css 스타일링을 하였다.

style 속성에 삼항 연산자를 사용하면 동적 스타일링을 할 수 있다.

 return (
    <form onSubmit={formSubmitHandler}>
      <div className="form-control">
        <label style={{ color: !isValid ? 'red' : 'black' }}>Course Goal</label>
        <input
          style={{
            borderColor: !isValid ? 'red' : '#ccc',
            background: !isValid ? 'salmon' : 'transparent'
          }}
          type="text"
          onChange={goalInputChangeHandler}
        />
      </div>
      <Button type="submit">Add Goal</Button>
    </form>
  );

동적 CSS 클래스 설정

백틱을 사용하면 className에서 동적으로 css 클래스를 설정할 수 있다.

  return (
    <form onSubmit={formSubmitHandler}>
      <div className={`form-control ${!isValid ? 'invalid' : ''}`}>
        <label>Course Goal</label>
        <input type="text" onChange={goalInputChangeHandler} />
      </div>
      <Button type="submit">Add Goal</Button>
    </form>
  );

Styled-Components 알아보기

styled components 를 사용하면 css 파일을 생성하지 않고 js 파일안에서 css를 만들 수 있으며,

협업을 할 때 css 클래스 네임이 응용프로그램의 다른 위치에서도 사용될 수 있습니다.

그럴 때 버그를 유발할 수 있는데, styled components를 사용하면 전역적으로 css 를 다룰 수 있다.

설치는 아래의 코드를 터미널에 입력하면된다.

npm install --save styled-components

그리고 vscode 확장팩에서 vscode-styled-components 를 입력하여 설치하자

import styled from 'styled-components'; // styled-components는 import 해서 사용

const Button = styled.button` // 상수를 선언하여 사용 / 첫 글자는 대문자로 한다.
  font: inherit;
  padding: 0.5rem 1.5rem;
  border: 1px solid #8b005d;
  color: white;
  background: #8b005d;
  box-shadow: 0 0 4px rgba(0, 0, 0, 0.26);
  cursor: pointer;
  &:focus {  // 이 버튼에 focus가 있으면 실행
    outline: none;
  }
  &:hover, // 이 버튼에 hover와 active 가 있으면 실행
  &:active {
    background: #ac0e77;
    border-color: #ac0e77;
    box-shadow: 0 0 8px rgba(0, 0, 0, 0.26);
  }
`;

 

Styled-Components: 동적 props 설정

  • FormControl을 JSX 에서 사용하고 props을 할당한다.
  • styled-components 에서 동적 스타일링에 해당하는 부분에서 ${ } 안에서 삼항 연산자를 사용한다.
import React, { useState } from 'react';
import styled from 'styled-components';

import Button from '../../UI/Button/Button';
import './CourseInput.css';

const FormControl = styled.div`
  margin: 0.5rem 0;
  & label {
    font-weight: bold;
    display: block;
    margin-bottom: 0.5rem;
    color: ${props => (props.invalid ? 'red' : 'black')};
  }
  & input {
    display: block;
    width: 100%;
    border: 1px solid ${props => (props.invalid ? 'red' : '#ccc')};
    background: ${props => (props.invalid ? '#ffd7d7' : 'transparent')};
    font: inherit;
    line-height: 1.5rem;
    padding: 0 0.25rem;
  }
  & input:focus {
    outline: none;
    background: #fad0ec;
    border-color: #8b005d;
  }
`;

const CourseInput = props => {
  const [enteredValue, setEnteredValue] = useState('');
  const [isValid, setIsValid] = useState(true);

  const goalInputChangeHandler = event => {
    if (event.target.value.trim().length > 0) {
      setIsValid(true);
    }
    setEnteredValue(event.target.value);
  };

  const formSubmitHandler = event => {
    event.preventDefault();
    if (enteredValue.trim().length === 0) {
      setIsValid(false);
      return;
    }
    props.onAddGoal(enteredValue);
  };

  return (
    <form onSubmit={formSubmitHandler}>
      <FormControl invalid={!isValid}>
        <label>Course Goal</label>
        <input type="text" onChange={goalInputChangeHandler} />
      </FormControl>
      <Button type="submit">Add Goal</Button>
    </form>
  );
};

export default CourseInput;

Styled-Components: 미디어 쿼리

styled-components를 사용할때 반응형 디자인은 미디어 쿼리를 사용한다.

@media 로 사용

import styled from 'styled-components';

const Button = styled.button`
  width: 100%;
  font: inherit;
  padding: 0.5rem 1.5rem;
  border: 1px solid #8b005d;
  color: white;
  background: #8b005d;
  box-shadow: 0 0 4px rgba(0, 0, 0, 0.26);
  cursor: pointer;
  
  // 미디어 쿼리
  @media (min-width: 768px) {
    width: auto;
  }
  
  &:focus {
    outline: none;
  }
  &:hover,
  &:active {
    background: #ac0e77;
    border-color: #ac0e77;
    box-shadow: 0 0 8px rgba(0, 0, 0, 0.26);
  }
`;

 

module.css 사용하기

css 확장자 명 앞에 modules. 을 입력하여 css 생성

module.css 를 사용하면 class에 고유한 값을 부여할 수 있다.

import React from 'react';

import styles from './Button.module.css';

const Button = props => {
  return (
    <button type={props.type} className={styles.button} onClick={props.onClick}>
      {props.children}
    </button>
  );
};
.button {
  font: inherit;
  padding: 0.5rem 1.5rem;
  border: 1px solid #8b005d;
  color: white;
  background: #8b005d;
  box-shadow: 0 0 4px rgba(0, 0, 0, 0.26);
  cursor: pointer;
}

.button:focus {
  outline: none;
}

.button:hover,
.button:active {
  background: #ac0e77;
  border-color: #ac0e77;
  box-shadow: 0 0 8px rgba(0, 0, 0, 0.26);
}

# Button.module.css

module.css 을 사용하여 동적 스타일링

import React, { useState } from 'react';

import Button from '../../UI/Button/Button';
import styles from './CourseInput.module.css';

// const FormControl = styled.div`
//   margin: 0.5rem 0;

//   & label {
//     font-weight: bold;
//     display: block;
//     margin-bottom: 0.5rem;
//     color: ${props => (props.invalid ? 'red' : 'black')};
//   }

//   & input {
//     display: block;
//     width: 100%;
//     border: 1px solid ${props => (props.invalid ? 'red' : '#ccc')};
//     background: ${props => (props.invalid ? '#ffd7d7' : 'transparent')};
//     font: inherit;
//     line-height: 1.5rem;
//     padding: 0 0.25rem;
//   }

//   & input:focus {
//     outline: none;
//     background: #fad0ec;
//     border-color: #8b005d;
//   }
// `;

const CourseInput = props => {
  const [enteredValue, setEnteredValue] = useState('');
  const [isValid, setIsValid] = useState(true);

  const goalInputChangeHandler = event => {
    if (event.target.value.trim().length > 0) {
      setIsValid(true);
    }
    setEnteredValue(event.target.value);
  };

  const formSubmitHandler = event => {
    event.preventDefault();
    if (enteredValue.trim().length === 0) {
      setIsValid(false);
      return;
    }
    props.onAddGoal(enteredValue);
  };

  return (
    <form onSubmit={formSubmitHandler}>
      <div
        className={`${styles['form-control']} ${!isValid && styles.invalid}`}
      >
        <label>Course Goal</label>
        <input type="text" onChange={goalInputChangeHandler} />
      </div>
      <Button type="submit">Add Goal</Button>
    </form>
  );
};

export default CourseInput;