79일차 (1) - React (동적 스타일 변경하기 - styled components, css module, Portal, useRef)

Yohan·2024년 6월 18일
0

코딩기록

목록 보기
121/156
post-custom-banner

동적으로 스타일 변경

  • 상태변수를 사용하여 동적으로 관리
  • 입력값 검증해서 동적 스타일 변경
const CourseInput = ({ onAdd }) => {

    // 목표 인풋에 입력한 값
    const [enteredText, setEnteredText] = useState('');

    // 입력값 검증을 통과했는지 여부를 상태관리
    const [isValid, setIsValid] = useState(true);

    const formSubmitHandler = e => {
        e.preventDefault();

        if (enteredText.trim().length === 0) {
            setIsValid(false);
            return;
        }

        const newGoalObject = {
          id: Math.random().toString(),
          text: enteredText
        };

        onAdd(newGoalObject); // Props Drilling

        setEnteredText('');
    };

    const goalChangeHandler = e => {

        const inputValue = e.target.value;

        // 입력값 검증
        if (inputValue.trim().length > 0) { // 글자수가 0보다 클때
            setIsValid(true);
        }

        setEnteredText(inputValue)
    }


    return (
            <div className="form-control">
                <label>나의 목표</label>
                <input
                    type="text"
                    onChange={goalChangeHandler}
                    value={enteredText}
                    style={{
                        backgroundColor: isValid ? 'transparent' : 'red',
                        borderColor: isValid ? 'black' : 'red',
                    }}
                />

export default CourseInput;

클래스 조작하여 동적 스타일 변경 (더 쉬움)

return (
        <form onSubmit={formSubmitHandler}>
            <div className={`form-control ${isValid ? '' : 'invalid'}`}>

						// isValid가 true면 '' 빈 문자열, 아니면 invalid 추가 

                <label>나의 목표</label>
                <input
                    type="text"
                    onChange={goalChangeHandler}
                    value={enteredText}
                />
            </div>
            <Button type="submit" >목표 추가하기</Button>
        </form>
    );

1. Styled-Components

  • 클래스 이름을 무작위로 생성하게 해주어서 협업 시 클래스 이름의 충돌을 방지 해준다.
  • css 파일 따로 만들지 않아도 됨.
  • props를 통해 컴포넌트의 스타일을 조건부로 변경 가능
import React from "react";
// import './Button.css';
import styled from "styled-components";

// 스타일된 컴포넌트
// 클래스명이 겹치지 않게됨 (많이 쓰이는 .btn , .button)
/*
  .fruit {
  
    &:hover {
    
    }
    & > .apple {

    }
  }
*/
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 {
    outline: none;
  }
  
  &:hover,
  &:active {
  background: #ac0e77;
  border-color: #ac0e77;
  box-shadow: 0 0 8px rgba(0, 0, 0, 0.26);
}
`;

// 컴포넌트
// const Button = ({ type, onClick, children}) => {
//   return (
//     <button type={type} className="button" onClick={onClick}>
//       {children}
//     </button>
//   );
// };

export default Button;

2. CSS Module

  • 각 컴포넌트에 대해 고유한 클래스 이름을 생성하여 스타일 충돌을 방지하
    이를 통해 CSS를 모듈화하여 각 컴포넌트에서 독립적으로 사용할 수 있게 해줌
  • 기존 css 파일명을 xxx.module.css로 변경
import React from 'react';
import styles from './CourseItem.module.css';

const CourseItem = ({ item, onDelete }) => {

  const deleteHandler = e => {
    console.log('삭제 해줘');
    // 여기서 App.js에게 삭제 대상의 id를 전달
    onDelete(item.id);
  }

  return <li className={styles['goal-item']} onClick={deleteHandler}>{item.text}</li>;
};

export default CourseItem; 
  • styles를 추가해주어 사용

React Portal

  • 모달의 종속성을 없애고, 전역에서 쓸 수 있도록 portal을 활용하는 방법
  • index.html
  • 기존엔 div#root만 존재했지만, 두개의 div를 추가
    <div id="root"></div>

    <!--  Modal의 내용이 들어갈 위치  -->
    <div id="overay-root"></div>

    <!--  Backdrop의 내용이 들어갈 위치  -->
    <div id="backdrop-root"></div>
  • ErrorModal.js에서 컴포넌트를 따로 빼서 작성 후,
    ReactDOM을 import 하고, createPortal() 함수를 사용
  • { createPortal(보낼 컴포넌트, 컴포넌트를 전달할 노드 요소) }
import React from 'react';
// porta을 사용하기 위한 불러오기
import ReactDOM from 'react-dom';

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

const BackDrop = ({ onClose }) => {
  return (
    <div
      className={styles.backdrop}
      onClick={onClose}
    ></div>
  );
};

const ModalOverlay = ({ title, message, onClose }) => {
  return (
    <Card className={styles.modal}>
      <header className={styles.header}>
        <h2>{title}</h2>
      </header>
      <div className={styles.content}>
        <p>{message}</p>
      </div>
      <footer className={styles.actions}>
        <Button onClick={onClose}>Okay</Button>
      </footer>
    </Card>
  );
};

const ErrorModal = ({ title, message, onClose }) => {
  return (
    <>
      {
        ReactDOM.createPortal(
          <BackDrop onClose={onClose} />
          , document.getElementById('backdrop-root')
        )
      }

{
        ReactDOM.createPortal(
          <ModalOverlay title={title} message={message} onClose={onClose} />
          , document.getElementById('overay-root')
        )
      }
    </>
  );
};

export default ErrorModal;

useRef

  • DOM에 직접 접근하지 않고 조작할 수 있게함
import React, { useRef } from 'react';

const MyComponent = () => {
  const myInputRef = useRef();

  const focusInput = () => {
    myInputRef.current.focus();
  };

  return (
    <div>
      <input ref={myInputRef} type="text" />
      <button onClick={focusInput}>Focus the input</button>
    </div>
  );
};

export default MyComponent;
  • input 요소를 myInputRef에 연결 -> 그러면 myInputRef.current는 input요소를 가리킴 -> focusInput 함수에서 myInputRef.current.focus();를 호출하면, 이 input 요소에 focus가 가게됨
profile
백엔드 개발자
post-custom-banner

0개의 댓글