JiSoo's Devlog

[Udemy React 완벽 가이드] Section 6 본문

Frontend/React

[Udemy React 완벽 가이드] Section 6

지숭숭숭 2024. 1. 4. 11:38

동적 인라인 스타일 설정하기

  • trim 메소드는 시작이나 끝부분에 과도하게 쓰인 공백을 제거해 주는 메소드
  • trim 메소드를 사용한 이유는 사용자가 수많은 공백을 입력한 경우 배제하기 위해서이다
  • enteredValue.trim().length === 0 은 입력되는 값이 비었다는 것을 알려준다
  • 유효하지 않은 값을 입력해 줬을 때 어떤 스타일을 적용하고 싶다면 state를 사용하면 되는데 state는 사용자가 제출했는지 입력한 것이 유효한지를 나타내는 지표가 된다
  • 가장 쉬운 방법은 레이블에 inline 스타일을 적용해 주는 방법인데 inline 스타일 props는 값으로 객체를 갖는다
  • 그 객체에서 이 컴포넌트를 위해 이 요소에 설정할 수 있는 자바스크립트에 있는 다양한 css 스타일의 속성을 목표로 한다
const CourseInput = (props) => {
  const [enteredValue, setEnteredValue] = useState("");
  const [isValid, setIsValid] = useState(true);

  const goalInputChangeHandler = (event) => {
    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="form-control">
        <label style={{ color: !isValid ? "red" : "black" }}>Course Goal</label>
        <input
          style={{
            bordeColor: !isValid ? "red" : "black",
            background: !isValid ? "salmon" : "transparent",
          }}
          type="text"
          onChange={goalInputChangeHandler}
        />
      </div>
      <Button type="submit">Add Goal</Button>
    </form>
  );
};

 

style={{ color: !isValid ? "red" : "black" }}

 

  • 단지 입력값이 유효하지 않은 경우에 조건부로 특정 스타일을 설정하기 때문에 inline 스타일로 덮어쓰는 것이다
  • inline 스타일이 최우선 순위를 차지하기 때문에 만족스럽지 않다
  • 리셋 기능 작업 ▼
const goalInputChangeHandler = (event) => {
    if (event.target.value.trim().length > 0) {
      setIsValid(true);
    }
    setEnteredValue(event.target.value);
  };
 

 

 

동적 스타일 연습

import React, { useState } from 'react';

export default function App() {
    const [isValid, setIsValid] = React.useState(false);
    
    const clickHandler =()=> {
        setIsValid(isValid => !isValid);
    }
    
    
    return (
        <div>
            <p style={{color: isValid ? 'red' : 'white'}}>Style me!</p>
            <button onClick={clickHandler}>Toggle style</button>
        </div>
    );
}
 
 

 

동적으로 CSS 클래스 설정하기

  • form-control이 invalid 클래스에 접근 가능하다고 선언할 수 있는데 이 말은 같은 요소에 있어야 된다는 뜻이며 이때 form-control과 invalid 사이에 공백이 없어야 한다
.form-control.invalid input {
  border-color: red;
  background: rgb(255, 215, 215);
}

.form-control.invalid label {
  color: red;
}
 
  • 이 css가 효과를 가지려면 invalid 클래스가 동적으로 추가되어야 한다
  • 동적인 값을 지정해 주기 위해 중괄호 사용
  • ` ` 을 사용해 주는데 이것은 싱글 따옴표가 아닌 백틱이 있는 문자열을 구성한다
  • 백틱 사이에 있는 것들은 일반적인 문자열로 취급될 것이다
  • 문자열에 동적인 값을 주입할 수도 있다 -> ${ } 이 중괄호 속 모든 콘텐츠는 자바스크립트 표현식이 될 수 있다
<div className={`form-control ${!isValid ? 'invalid' : ''}`}>
 
  • 클래스 이름이 form-control 뒤에 아무것도 없거나 form-control invalid가 될 것이다

 

 

동적 CSS 클래스 연습

import React, {useState} from 'react';

export default function App() {
    const [isValid,setIsValid] = React.useState(false);
    
    const clickHandler =()=> {
        setIsValid(isValid=>!isValid)
        
    }
    
    return (
        <div>
            <p className={ isValid ? "active" : ""}>Style me!</p>
            <button onClick={clickHandler}>Toggle style</button>
        </div>
    );
}
 
 
 

 

Styled Components 소개

  • DOM 요소 어딘가에 같은 이름의 클래스를 갖고 있다면 영향을 미치게 된다
  • 응용 프로그램의 다른 위치에서 사용되는 것을 막기 위한 방법 2가지가 있다
  • 첫 번째 방법은 styled components 패키지를 사용하는 것
  • styled components는 특정 스타일이 첨부된 컴포넌트를 구축할 수 있도록 도와주는 패키지인데 이 스타일이 첨부되는 컴포넌트에만 영향을 미치고 다른 컴포넌트에는 전혀 영향을 미치지 않는다
import React from 'react';
import styled from 'styled-components';

const Button = styled.button``;

export default Button;
 
  • styled.button``; 이 구문은 태그드 템플릿 리터럴이라고 부르는데 자바스크립트의 기본 기능으로 어떤 프로젝트에서도 사용 가능하다
  • 여기서 button은 styled 객체의 메소드이다
  • 백틱에 전달하는 것은 특별한 방식으로 이 메소드에 전달될 것이다
  • 백틱에 우리가 전달하는 것이 결국 Button 메소드로 간다는 것만 알면 된다
  • button 메소드가 새로운 button 컴포넌트를 반환한다
  • styled 패키지는 모든 html 요소에 대한 메소드를 갖고 있다.
  • 단락을 위한 p메소드와 h1, h2 태그를 위한 h1, h2 그리고 div를 생성하기 위한 div 등이 있다
  • 전체 표현식은 button을 반환하지만 백틱 사이에 전달한 스타일이 있는 button 일 것이다
  • 백틱 구문을 여러 줄의 문자열을 작성할 수 있다는 장점이 있다
  • 백틱 사이에 전달할 스타일이 button에 직접적으로 영향을 줄 것이다
  • 그렇기 때문에 선택자를 삭제하고 스타일을 붙여 넣으면 그것들은 button 메소드가 호출되어 반환하는 button 요소에 추가되고 상수 button까지 영향을 미칠 것이다
  • styled components에서 제공하는 &를 사용하면 되는데 이것은 여기서 생성한 이 컴포넌트에 대해 이 경우에 특별한 가상 선택자를 사용하겠다고 패키지에게 선언하는 것이다 -> &:hover , &:active (button:hover, button:active)
  • react 임포트 구문은 삭제해도 된다 - JSX 구문을 이제 사용하지 않기 때문에
  • 모든 클래스는 고유한 이름을 가지기 때문에 앱에 있는 다른 컴포넌트에 영향을 주지 않는다

 

 

 

Styled Components & 동적 Props

  • 파일에서 다른 컴포넌트에도 사용되는 컴포넌트를 갖고 있다면 동일한 파일에서 그 두 컴포넌트를 가질 수도 있다
  • &는 항상 생성된 컴포넌트를 다시 참조한다

 

CourseInput.js

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;
  }

  & input {
    display: block;
    width: 100%;
    border: 1px solid #ccc;
    font: inherit;
    line-height: 1.5rem;
    padding: 0 0.25rem;
  }

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

  &.invalid input {
    border-color: red;
    background: rgb(255, 215, 215);
  }

  &.invalid label {
    color: red;
  }
`;

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 className={!isValid && "invalid"}>
        <label>Course Goal</label>
        <input type="text" onChange={goalInputChangeHandler} />
      </FormControl>
      <Button type="submit">Add Goal</Button>
    </form>
  );
};

export default CourseInput;
 
  • 일부 props에 따라 스타일을 동적인 방식으로 바꿀 수 있다
  • props가 유효한지 체크해서 유효하지 않을 때와 유효할 때 스타일 지정
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 & 미디어 쿼리

  • 미디어 쿼리는 올바른 모양을 얻는데 중요한 것
  • 미디어 쿼리를 추가하고 기준을 정의하면 된다
  • 미디어 쿼리에 대한 조건을 만족할 때 컴포넌트에 적용할 스타일만 있으면 된다
  • 모바일에서는 큰 버튼, 화면이 더 커지면 필요한 만큼 공간 차지
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;
  }
 
모바일
 

 

 

 

CSS 모듈 사용하기

  • css 모듈을 사용하고 싶다면 css 파일을 임포트 할 때 styles나 classes를 임포트 해준다
  • 화면 뒤에서 벌어지는 코드 변환을 위해 css 파일 이름을 바꿔줘야 한다 -> Button.module.css
  • 파일 이름 바꿔주는 것은 기본적으로 css 모듈이 작동하도록 코드를 변환하라고 컴파일 프로세스에게 보내는 신호이다
  • 버튼 클래스명을 {styles} 동적인 값으로 주는데 이것은 객체이며 그 객체 안에 파일에서 프로퍼티로 정의하는 모든 클래스를 갖는다. 그래서 css 파일에 button 클래스를 추가했다면 button 프로퍼티를 갖게 되는 것이다
className={styles.button}
 
  • css 클래스나 css 파일을 가지고 그 클래스 이름을 기본적으로 고유하게 바꾸는 일을 한다
  • 모든 컴포넌트에 대해 임포트하고 있는 모든 클래스의 이름을 바꾸기 때문에 모든 css 파일을 고유하게 만든다
  • 고유한 버전의 스타일과 클래스 생성
  • css 모듈의 개념은 css 파일에서 설정한 css 스타일의 범위가 이 파일을 임포트 하는 컴포넌트에 한정된다
  • 임포트 된 스타일 객체의 클래스에 속성으로 접근하기 때문에 css 파일로 작업
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>
  );
};

export default Button;
 

 

 

CSS 모듈을 사용한 동적 스타일

  • form-control은 유효하지 않은 프로퍼티 이름인데 프로퍼티에 접근하기 위해 대괄호와 따옴표로 이름을 감싸주면 된다 -> 문자열은 자바스크립트 객체에서 유효한 키이기 때문에
  • 중간에 대시(-)가 없는 다른 css 클래스 이름을 선택할 수도 있다
  • 변환된 invalid 클래스 버전을 추가하려면 백틱구문으로 돌아가 입력할 값에 문자열을 생성할 수 있다
  • 첫 번째 입력할 값은 변환된 클래스 이름을 입력하는데 이것은 스타일 객체에서 이 문자열로 추출한 것이다
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>
  );
 
  • styled 컴포넌트와 다른 중요한 점은 css에서는 선택자가 필요하다
@media (min-width: 768px) {
  .button {
    width: auto;
  }
}
 

 

728x90