[포스코 x 코딩온] 웹 풀스택 13주차 회고 -1

sima·2023년 10월 3일
0

KDT web-8

목록 보기
15/17
post-thumbnail

SASS, SCSS

css 코드의 재활용성과 코드 가독성을 높여 유지보수가 좋은 CSS 전처리기 중 하나

sass와 scss의 차이

sass : ;(세미콜론)과 {}를 사용하지 않고 tab을 이용해 스타일 정의
scss : 기존의 css파일과 비슷한 문법 사용
sass와 scss 모두 변수 선언 시 $ 사용

React에서의 SASS 사용

npm i node-sass

예시 코드

// SassComponent.js
import './SassComponent.scss'
export default function SassComponent() {
    return <div className="SassComponent">
        <div className="box red"></div>
        <div className="box orange"></div>
        <div className="box yellow"></div>
        <div className="box green"></div>
        <div className="box blue"></div>
        <div className="box navy"></div>
        <div className="box purple"></div>
    </div>
}

//SassComponent.scss
@import './utils.scss';

.SassComponent {
  display: flex;
  //중첩
  .box {
    @include box(100px);
    //width: 100px;
    //height: 100px;
    border: 1px solid black;

    //& : 중첩 안에서 키워드는 부모 선택자를 참조하여 치환
    // 하나의 태그에 여러 클래스 같이 존재할 때
    &.red {
      background-color: $color-red;
    }

    &.orange {
      background-color: $color-orange;
    }

    &.yellow {
      background-color: $color-yellow
    }

    &.green {
      background-color: $color-green;
    }

    &.blue {
      background-color: $color-blue;
    }

    &.navy {
      background-color : $color-navy;
    }

    &.purple {
      background-color: $color-purple;
    }
  }
  
  .btn {
  	padding : 10px;
    margin : 10px;
    border : 1px solid black;
  }
  
  .btn-primary {
  	@extend .btn;
    background-color : blue;
  }

  
//_utils.scss
$color-red : #ff0000;
$color-orange : orange;
$color-yellow : yellow;
$color-green : green;
$color-blue : blue;
$color-navy : navy;
$color-purple : #b734b7;

@mixin box($size) {
  width: $size;
  height: $size;
}

특정 태그 내부에 있는 태그의 css에 접근할 때, 중첩 사용
SCSS 파일명 앞에 _ 붙이면 파일단위로 분리되어 컴파일되지 않음, 보통의 경우 css 변수나 코드블록을 미리 정의해놓고 사용(@import로 정의된 파일 가져다 사용)
@mixin으로 미리 css 코드블록을 정의 가능, 정의한 코드블록을 사용할 때 @include 사용
@extend로 다른 css 선택자의 스타일을 그대로 가져다 사용 가능


Styled Component

css를 외부 파일에 의존하지 않고, 컴포넌트 내부에 직접 넣어 사용
각각의 컴포넌트 안에 css가 존재하기 때문에 스타일이 전역적으로 중첩되지 않음

Styled-Component 사용

npm i styled-components

(VSCode IDE 사용 시 vscode-styled-components 플러그인 설치)

예시 코드

import styled from 'styled-components';

const _Box = styled.div`
  background-color: blue;
  width: 100px;
  height: 100px;
`

const _Box2 = styled.div`
  background-color: ${props => props.color};
  width: 200px;
  height: 200px;
`

const _Circle = styled(_Box2)`
  border-radius: 100px;
`

const _Btn = styled.button`
  background-color: blue;
  color: pink;
  padding: 10px 15px;
  border-radius: 4px;
`

const _Input = styled.input.attrs({ required : true })`
`

const _Box3 = styled.div`
  width: 200px;
  height: 100px;
  background-color: aqua;
  line-height: 100px;
  text-align: center;
  
  ${_Input} {
    background-color: purple;
  }
 
  .ptag {
    color : indianred;
    font-weight: bold;
    
    &:hover {
      font-size: 32px;
    }
  }
`
export default function StyledComponent() {
    return (
        <div>
            <_Box3>
                <p className="ptag">Hello Styled</p>
                <_Input></_Input>
            </_Box3>
            <_Box></_Box>
            <_Box2 color="green" as="header"></_Box2>
            <_Circle color="red"></_Circle>
            <_Btn as="a">클릭</_Btn>
            <_Input></_Input>
        </div>
    )
}

import styled from 'styled-components'로 스타일 컴포넌트 사용 준비
styled.태그명에 백틱을 사용, 백틱 안에 스타일 정의
${}로 props 이용해 스타일 정의 가능
styled(다른 컴포넌트명) 으로 다른 스타일 컴포넌트의 스타일을 상속 가능
styled.태그명.attrs()로 태그의 속성값 접근, 정의 가능
중첩 css 사용 시, ${}로 해당 컴포넌트 내부의 다른 컴포넌트 css를 지정하거나, 일반 css 문법으로 내부의 태그 css 작성 가능
기존에 작성한 컴포넌트 태그를 as를 이용해 태그를 바꾸어 사용 가능


React Router

요청된 url에 따라 다른 컴포넌트를 보여주기 위해 사용하는 라이브러리

설치

//버전 6 지정 설치
npm i react-router-dom@6

BrowserRouter

HTML5를 지원하는 브라우저의 주소 감지, 새로고침을 하지 않아도 새로운 컴포넌트를 렌더링
BrowserRouter는 바뀌는 부분의 최상단에 위치해야 함

Routes, Route

요청한 url 경로에 따라 일치하는 컴포넌트를 렌더링해주도록 하는 역할
Route로 구체적인 컴포넌트 렌더링 결정

기존 HTML의 a 태그의 새로고침 렌더링과 달리, Link는 컴포넌트 페이지 전환을 방지하며 경로를 변경

예시 코드

import {BrowserRouter, Routes, Route} from "react-router-dom";
import Header from "./Components/Header";
import Home from "./Components/Home";
import About from "./Components/About";
import NotFound from "./Components/NotFound";
import User from "./Components/User";
import Redirect from "./Components/Redirect";
import UserDetail from "./Components/UserDetail";
import App from "./App";
import Error from "./Components/Error";
import Comment from "./Components/Comment";

export default function Router() {
    return (
        <>
            <BrowserRouter>
                <Header></Header>
                <Routes>
                    <Route path="/" element={<Home/>}></Route>
                    <Route path="/about" element={<About/>}></Route>
                    <Route path="/user" element={<User/>}></Route>
                    <Route path="/user/:id" element={<UserDetail/>}></Route>
                    <Route path="/redirect" element={<Redirect/>}></Route>
                    <Route path="*" element={<NotFound/>}></Route>
                </Routes>
            </BrowserRouter>
        </>
    )
}

Routepath 속성으로 url 경로 지정, element로 렌더링할 컴포넌트 입력
Linkto 속성으로 url 경로 지정
지정한 url 이외에 다른 url 에러 요청 처리시 path* 사용


CreateBrowserRouter

react-router v6.4 이후부터 제공하는 컴포넌트 렌더링 라우터

Outlet

부모 라우트 컴포넌트 내에서 사용되어, 부모 라우트의 url과 일치하는 자식 라우트 컴포넌트를 렌더링
context 속성을 통해 자식 라우트에 데이터 전송 가능, 자식 라우트에서는 useOutletContext() 로 접근 가능

useParams

url 경로에 :로 설정해 요청시 받는 파라미터를 컴포넌트 내부에서 가져옴

useSearchParams

url 경로에 쿼리스트링 형식으로 요청을 받는 API에 대해 받는 파라미터를 컴포넌트 내부에서 사용

useNavigate

Link 컴포넌트를 사용하지 않고 다른 페이지로 이동해야 하는 경우 사용

예시 코드

//PracRouter.js
import {createBrowserRouter} from "react-router-dom";
import Prac from "./App";
import NameKdt from "./PracComponents/NameKdt";
import New from "./PracComponents/New";

const router = createBrowserRouter([
    {
        path : '/',
        element : <Prac/>,
    },
    {
        path : 'student',
        children : [
            {
                path : ':value',
                element : <NameKdt/>,
            },
            {
                path : 'new',
                element : <New/>,
            }
        ]
    }
]);

export default router;

//index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import {RouterProvider} from "react-router-dom";
import Router from "./Router";
import PracRouter from "./PracRouter";

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    // <App />
    <RouterProvider router={PracRouter}></RouterProvider>
);

//NameKdt.js
import {useNavigate, useParams, useSearchParams} from "react-router-dom";
import {useEffect} from "react";

export default function NameKdt() {
    const { value } = useParams();

    const navigate = useNavigate();

    const goBack = () => {
        navigate(-1);
    }
    return (
        <>
            <div>학생의 이름은 <span style={{ color : 'green' }}>{value}</span>입니다.</div>
            <button onClick={goBack}>이전페이지로</button>
        </>
    )
}

//New.js
import {useNavigate, useSearchParams} from "react-router-dom";

export default function New() {
    const [searchParams, setSearchParams] = useSearchParams();
    console.log(searchParams.get('name'));
    const navigate = useNavigate();
    const goBack = () => {
        navigate(-1);
    }
    return (
        <>
            <div>학생의 이름은 <span style={{ color : 'green' }}>new</span>입니다.</div>
            <div>실제 이름은 <span style={{ color : 'red' }}>{searchParams.get('name')}</span></div>
            <button onClick={goBack}>이전페이지로</button>
        </>
    )
}

CreateBrowserRouter 사용 시, BrowserRouter로 감싸지 않고, index.js에서 RouterProvider를 사용해 라우터 제공, router 속성으로 라우터 가져와 사용
createBrowserRouter() 함수 사용하여 라우터 생성, path는 요청할 url 을 적고, element로 요청 url에 렌더링할 컴포넌트 추가
children 속성으로 url 중첩 라우팅 사용 가능, 이외에 errorElement 속성으로 잘못된 url 접근에 대한 컴포넌트 렌더링 가능

NameKdt 컴포넌트의 path: 사용해 파라미터를 받으므로, 해당 컴포넌트에서 useParams() 사용해 값을 가져옴
navigate 사용 시, 변수에 useNavigate()로 정의해 해당 변수 사용(-1 = 이전 페이지, 문자열로 직접 url 지정 가능)
New 컴포넌트에 대한 요청을 받을 때 쿼리스트링 방식 사용, useSearchParams()로 값을 가져옴, 배열 값 중 setSearchParams로 직접 파라미터 지정도 가능
searchParams.get() 함수로 요청 시 받은 파라미터 접근 가능

React Hook Form

React에서의 Form의 상태관리와 유효성 검사를 지원

설지

npm i react-hook-form

예시 코드

import {useForm} from "react-hook-form";

export default function Form() {
    const { register, handleSubmit, watch, formState : {errors} } = useForm();

    const onValid = (data) => {
        console.log(data);
    };

    // const onInvalid = (error) => {
    //     console.log('err', error);
    // };

    // console.log(watch('password'));
    console.log('errors', errors);

    return (
        <>
            <form onSubmit={handleSubmit(onValid)}>
                <input type="text" {...register('username', {
                    required : '이름을 입력하세요',
                    minLength : {
                        message : '최소 2글자 이상', value : 2
                    }
                })}/>
                <div>{errors.username?.message}</div>
                <input type="text" {...register('email', {
                            required : '이메일을 입력하세요',
                            validate : {
                                useGmail : (value)=> {
                                    return value.includes('gmail.com') || 'gmail로만 가입 가능합니다.';
                                }
                            }
                })}/>
                <div>{errors.email?.message}</div>
                <input type="text" {...register('password')}/>
                <button type="submit">Submit</button>
            </form>
        </>
    );
}

useForm() 함수로 react hook form 요소들을 가져와 사용
register로 입력 요소에 연결, 유효성 검사 설정
폼 제출 시 handleSubmit으로 처리, 두개의 콜백함수가 인자로 오는데, 첫번째 함수는 유효성 검사가 통과했을 때 실행되는 함수로 필수 작성해야 하고, 두번째 함수는 유효성 검사가 실패했을때 실행하는 함수로 선택적으로 작성 가능
watch로 폼 필드의 값을 실시간으로 관찰 가능
formState는 객체형식으로, 폼의 상태를 나타내는 여러 상태들을 가지고 있음(errors, isValid, isDirty, isSubmitted 등)

register 함수 예시 코드

import {useForm} from "react-hook-form";

export default function PracComponent() {
    const { register, handleSubmit, watch, formState : {errors} } = useForm();

    const onValid = (data) => {
        console.log(data);
    }
return (
    <>
        <form onSubmit={handleSubmit(onValid)}>
            <input type="text" {...register('name', {
                required : '이름은 필수항목입니다.'
            })}/>
            <div>{errors.name?.message}</div>
            <input type="number" {...register('age', {
                min : {
                    message : '0 이상의 숫자만 입력가능합니다.',
                    value : 0
                }
            })}/>
            <div>{errors.age?.message}</div>
            <button type="submit">제출</button>
        </form>
    </>
);
}

register() 함수의 첫번째 인자는 태그 요소의 이름, 두번째 인자는 객체형식으로 required, min, maxLength 등 여러 조건 설정 가능
조건 내부에 message 속성으로 유효성 검사 실패 시 나타날 문구와 같이 작성 가능
validate 속성으로 커스텀 유효성 검사 작성 가능

0개의 댓글