React - styling

haahi·2023년 3월 3일

React

목록 보기
5/6
post-thumbnail

현재 만들어진 프로젝트는 input 창에 아무것도 입력하지 않아도 Add Goal버튼을 누르면 빈 값이 추가가 가능한데, 만약 사용자가 입력한 값이 빈 값이면 추가를 하지 못하게 막고, 값이 유효하지 않다고 표시하는 기능을 만들어보았다.

inline styling

// 기존 코드
const CourseInput = props => {
  const [enteredValue, setEnteredValue] = useState('');

  const goalInputChangeHandler = event => {
    setEnteredValue(event.target.value);
  };

  const formSubmitHandler = event => {
    event.preventDefault();
    props.onAddGoal(enteredValue);
  };

  return (
    <form onSubmit={formSubmitHandler}>
      <div className="form-control">
        <label>Course Goal</label>
        <input type="text" onChange={goalInputChangeHandler} />
      </div>
      <Button type="submit">Add Goal</Button>
    </form>
  );
};


// 변경된 코드
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();

    // 만약 사용자가 공백을 입력하면 실행 X
    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={{
            borderColor: !isValid ? "red" : "black",
            background: !isValid ? "salmon" : "transparent",
          }}
          type="text"
          onChange={goalInputChangeHandler}
        />
      </div>
      <Button type="submit">Add Goal</Button>
    </form>
  );
};

submit 기능을 해주는 Add Goal버튼을 클릭했을때 작동하는 formSubmitHandler 함수에서 사용자가 입력한 값을 추가하는 동작이 이뤄지기 전에 if를 사용하여 사용자가 공백을 입력하면 그 함수를 빠져 나오게 return 을 써줬다.

그리고 사용자가 이를 알 수 있도록 style도 적용하기 위해 useState를 사용하여 코드를 작성했다.
isValid의 기본값은 true로 사용자가 유효하지 않을 값을 입력하였을 경우 이를 false로 변경하여 스타일을 동적으로 바꿀 수 있도록 하였다.

이렇게 변경된 isValid를 JSX문 안에서 삼항 연산자를 사용해 inline으로 작성하여 디자인을 변경하였다.

styled-components

하지만 이렇게 inline 방식으로 적용된 스타일이 최우선으로 적용되기에 기존에 갖고 있던 스타일을 덮어버려 만족스럽지 않다. 이를 해결하기 위해 styled-components를 사용해보았다.

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) => {
				.
                .
                .
  return (
    <form onSubmit={formSubmitHandler}>
      // props로 invalid 넘김
      <FormControl invalid={!isValid}>
        <label>Course Goal</label>
        <input type="text" onChange={goalInputChangeHandler} />
      </FormControl>
      <Button type="submit">Add Goal</Button>
    </form>
  );
};

기존 div 태그를 컴포넌트로 변경하여 그 안에 원하는 스타일을 적용시켜 준다. 이때 styled.div`` 이런식으로 템플릿 리터럴을 사용해 스타일을 감싸준다.
이때, props로 받은 invalid를 통해 동적으로 스타일을 적용해준다. invalid가 false라면 값이 유효하지 않으니 사용자가 이를 알 수 있도록 빨간색으로 표시해준다.
이렇게 styled-components를 사용하면 .css 파일로 스타일을 적용하면 같은 class name이 있다면, 내가 적용하고 싶은 컴포넌트에만 영향을 주는 것이 아닌 다른 컴포넌트의 스타일도 변경이 되는데, 이를 유일한 class 로 만들어주기 때문에 내가 원하는 컴포넌트에만 스타일을 적용할 수 있다.

CSS module

하지만 styled-components는 컴포넌트와 스타일이 한 파일에 같이 정의도이어 있기 때문에 조금 복잡한 느낌이 있어 이를 분리해보았다.

import styles from "./CourseInput.module.css";

const CourseInput = (props) => {
  				.
                .
                .
  return (
    <form onSubmit={formSubmitHandler}>
      // isValid가 false이면 className에 invalid를 추가함
      <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>
  );
};

CSS module을 사용하기 위해서는 CSS 파일명에 .module을 추가하여 하고, 이를 styled로 import 해야 한다.
styled-components를 사용할 때 변경되었던 컴포넌트를 다시 div로 바꿔준 뒤 className이 동적으로 변경될 수 있도록 && 연산자를 사용했다.
이렇게 만들어진 CSS module도 해당 컴포넌트에만 스타일이 적용되는데 그 이유는 CSS module이 자동으로 class를 "컴포넌트 이름클래스 이름고유한 해시값"으로 설정해주기 때문이다.


사용자가 유효하지 않은 값 (공백)을 입력하면 위와 같이 사용자가 알 수 있도록 표시해주며, 목록에 추가가 되지 않는다.

0개의 댓글