목표

  • Formik 컴포넌트 사용하기
  • Yup 패키지로 유효성 검사(validation) 처리하기

 


결과 화면

 


1. yup 설치하기

yup은 값 구문 분석 및 유효성 검사를 위한 스키마 빌더이다. (타입스크립트도 지원)

 

https://www.npmjs.com/package/yup?activeTab=readme 

yup에 대한 자세한 설명은 위의 링크를 참고한다.

yarn add yup
또는 
npm install yup

 

2. yup 스키마 작성하기

min() : 최소 글자수

max() : 최대 글자수

matches() : 정규 표현식

required() : 필수값

 

input 유효성 검사에서 가장 많이 사용하는 4가지 메서드이고,

email, url 등 다양한 메서드들을 사용하고 싶다면 yup 공식 문서를 참고한다.

import * as Yup from 'yup'

const joinSchema = Yup.object().shape({
  userId: Yup.string()
    .min(4, '4자 이상의 아이디를 입력해 주세요.')
    .max(10, '10자 이하의 아이디를 입력해 주세요.')
    .matches(/^(?=.*[a-z])(?=.*[0-9]).{4,10}$/, '영문 소문자와 숫자를 조합해서 아이디를 입력해 주세요.')
    .required('아이디를 입력해 주세요.'),
  password: Yup.string()
    .min(4, '4자 이상의 비밀번호를 입력해 주세요.')
    .max(10, '10자 이하의 비밀번호를 입력해 주세요.')
    .matches(/^(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[!@#$%^*+=-]).{4,10}$/, '영문, 숫자, 특수문자를 조합해서 비밀번호를 입력해 주세요.')
    .required('비밀번호를 입력해 주세요.')
})

 

3. Formik 컴포넌트 설치하기

Formik은 Reac와 React Native 위한 form 오픈 소스 라이브러리이다.

입력 유효성 검사, 서식 지정, 배열 및 오류 처리 등 form 코드를 간단하게 작성할 수 있다.

 

https://formik.org/docs/overview

Formik에 대한 자세한 설명은 위의 링크를 참고한다.

yarn add formik
또는
npm install formik

 

4. Form 컴포넌트 적용하기

Formik, Form, Field, ErrorMessage 컴포넌트는 Formik 라이브러리에서 제공하는 컴포넌트이다.

 

initialValues : 초기값

validationSchema : yup 스키마 변수

onSubmit : form이 제출됐을 때 동작하는 함수

 

Field와 ErrorMessage 컴포넌트에 intivalValues에 해당하는 name을 작성한다.

button의 type을 submit으로 한다.

 

폼을 제출하면 알아서 validation 처리가 이루어진다.

import * as Yup from 'yup'
import { Formik, Form, Field, ErrorMessage } from 'formik'
...

const joinSchema = Yup.object().shape({
  userId: Yup.string()
    .min(4, '4자 이상의 아이디를 입력해 주세요.')
    .max(10, '10자 이하의 아이디를 입력해 주세요.')
    .matches(/^(?=.*[a-z])(?=.*[0-9]).{4,10}$/, '영문 소문자와 숫자를 조합해서 아이디를 입력해 주세요.')
    .required('아이디를 입력해 주세요.'),
  password: Yup.string()
    .min(4, '4자 이상의 비밀번호를 입력해 주세요.')
    .max(10, '10자 이하의 비밀번호를 입력해 주세요.')
    .matches(/^(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[!@#$%^*+=-]).{4,10}$/, '영문, 숫자, 특수문자를 조합해서 비밀번호를 입력해 주세요.')
    .required('비밀번호를 입력해 주세요.')
})

const Join = () => {
  ...

  return (
    <div className="join">
      <Formik
        initialValues={{
          userId: '',
          password: ''
        }}
        validationSchema={ joinSchema }
        onSubmit={ values => { dispatch(postJoin(values)) }}>
        <Form>
          <div>
            <Label htmlFor="userId">Id</Label>
            <Field name="userId" placeholder="아이디를 입력해 주세요."/>
            <ErrorMessage name="userId" component="span" className="error" />
          </div>

          <div>
            <Label htmlFor="password">Password</Label>
            <Field type="password" name="password" placeholder="비밀번호를 입력해 주세요."/>
            <ErrorMessage name="password" component="span" className="error" />
          </div>
          
          <Button type="submit" children="Confirm" variant="primary"/>
        </Form>
      </Formik>
    </div>
  )
}

export default Join

결과 화면

 


1. styled-components, @types/styled-components 설치하기

styled-components 패키지와 @types/styled-components 패키지를 설치한다.

 

자바스크립트일 경우, styled-components 패키지만 설치해도 되지만,

타입스크립트에서 사용하기 위해서는 @types/styled-components 패키지도 설치해야 한다.

yarn add styled-components
또는
npm install styled-components
yarn add @types/styled-components
또는
npm install @types/styled-components

 

2. Button 컴포넌트 만들기

2-1. StyledButton 만들기

  • src/components/Button.tsx

styled-components를 import 한다.

StyledButton 컴포넌트를 만든 후, `` 안에 css를 작성한다.

StyledButton 컴포넌트를 적용할 Button 컴포넌트를 만든다. 

import styled from 'styled-components'

const StyledButton = styled.button`
  // 필요한 css를 작성한다.
  
  width: 100%;
  height: 50px;
  ...
`

const Button = () => {
  return (
    <StyledButton>버튼</StyledButton>
  )
}

export default Button

 

2-2. StyledButton에 props 적용하기

props로 값을 받기 위해서는 ${(props) => props.~} 형태로 받아야 한다.

 

backgroundColor 변수를 만들고, 필요한 값을 작성한다. (background-color가 필요했을 뿐, 다른 값들도 가능하다.)

props로 넘길 값(backgroundColor)의 타입을 정의하기 위해 interface를 만든다.

StyledButton 컴포넌트에 타입(ButtonProps)과 props로 넘길 값을 정의한다.

Button 컴포넌트의 파라미터에 variant 값을 넘긴다.

import styled from 'styled-components'

const backgroundColor = {
  primary: '#677987',
  secondary: '#B4B6AC'
}

interface ButtonProps {
  readonly variant: 'primary' | 'secondary'
}

const StyledButton = styled.button<ButtonProps>`
  width: 100%;
  height: 50px;
  background-color: ${(props) => backgroundColor[props.variant]};
  text-align: center;
`

const Button = ( { variant }: ButtonProps) => {
  return (
    <StyledButton variant={variant}>버튼</StyledButton>
  )
}

export default Button

 

2-3. 부모 컴포넌트에 값 전달하기

Button 컴포넌트의 텍스트도 props로 전달하기 위해서 children을 사용한다.

 

interface에 children의 타입을 정의한다.

Button 컴포넌트의 파라미터에 childred 값을 넘긴다.

import styled from 'styled-components'

const backgroundColor = {
  primary: '#677987',
  secondary: '#B4B6AC'
}

interface ButtonProps {
  children: string
  readonly variant: 'primary' | 'secondary'
}

const StyledButton = styled.button<ButtonProps>`
  width: 100%;
  height: 50px;
  background-color: ${(props) => backgroundColor[props.variant]};
  text-align: center;
`

const Button = ({ children, variant }: ButtonProps) => {
  return (
    <StyledButton variant={variant}>{children}</StyledButton>
  )
}

export default Button

 


최종 코드

  • src/components/Button.tsx
import styled from 'styled-components'

const backgroundColor = {
  primary: '#677987',
  secondary: '#B4B6AC'
}

const textColor = {
  primary: '#FCFCFC',
  secondary: '#FCFCFC'
}

interface ButtonProps {
  children: string
  readonly variant: 'primary' | 'secondary'
}

const StyledButton = styled.button<ButtonProps>`
  width: 100%;
  height: 50px;
  border-radius: 5px;
  background-color: ${(props) => backgroundColor[props.variant]};
  color: ${(props) => textColor[props.variant]};
  font-size: 16px;
  text-align: center;
  transition: all 0.3s;
  
  &:hover {
    opacity: 0.8;
  }
`

const Button = ({ children, variant }: ButtonProps) => {
  return (
    <StyledButton variant={variant}>{children}</StyledButton>
  )
}

export default Button

 

  • src/App.tsx

Button 컴포넌트를 import 한다.

props로 넘길 값들(children, variant)을 작성한다.

 

Title 컴포넌트도 같은 방식으로 작성됐다.

import Title from '../../components/base/Title'
import Button from '../../components/form/Button'
import './index.scss'

const App = () => {
  return (
    <>
      <div className="board-create">
        <Title children="Write content"/>
        
        <Button children="Confirm" variant="primary"/>
        <Button children="Cancel" variant="secondary"/>
      </div>
    </>
  )
}

export default App

결과화면

 


1. react-router-dom 설치하기

react-router-dom 패키지를 설치한다.

설치가 완료되면 packae.json 파일에서 확인할 수 있다.

yarn add react-router-dom
또는
npm install react-router-dom

 

2. BrowerRouter 컴포넌트를 최상위 태그에 감싸기

  • src/index.tsx

App 컴포넌트 위에 BrowerRouter 컴포넌트를 감싼다.

import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import App from './App'

const root = ReactDOM.createRoot (
  document.getElementById('root') as HTMLElement
)

root.render(
  <React.StrictMode>
    <BrowserRouter>
      <App/>
    </BrowserRouter>
  </React.StrictMode>
)

 

3. path를 설정하기

  • src/App.tsx

path와 그에 해당하는 element 컴포넌트를 작성한다.

import React from 'react'
import { Routes, Route } from 'react-router-dom'
import Layout from './components/layouts/Layout'
import MainPage from './pages/main'
import BoardPage from './pages/board'
import './assets/scss/common.scss'

const App = () => {
  return (
    <>
      {
        <Layout>
          <Routes>
            <Route path="/" element={<MainPage/>}/>
            <Route path="/board" element={<BoardPage/>}/>
          </Routes>
        </Layout>
      }
    </>
  )
}

export default App

결과 화면

 


1. node-sass 설치하기

node-sass 패키지를 설치한다.

설치가 완료되면 packae.json 파일에서 확인할 수 있다.

yarn add node-sass
또는
npm install node-sass

 

2. SCSS 작성하기

  • src/assets/scss/components/header.scss
header {
  width: 100%;

  .inner {
    display: flex;
    justify-content: space-between;
    align-items: center;
    height: 80px;

    h1 {
      a {
        font-family: 'Cherry Bomb One', cursive;
      }
    }

    nav {
      ul {
        display: flex;
        justify-content: space-between;
        align-items: center;

        li {
          padding-left: 20px;
        }
      }
    }
  }
}

 

  • src/components/layouts/Heaser.tsx

작성한 scss 파일을 상단에 import 시킨다.

import '../../assets/scss/components/header.scss'

const Header = () => {
  return (
    <>
      <header>
        <div className="inner">
          <h1><a href="/">BOB</a></h1>

          <nav>
            <ul>
              <li><a href="/">menu01</a></li>
              <li><a href="/">menu02</a></li>
              <li><a href="/">menu03</a></li>
            </ul>
          </nav>
        </div>
      </header>
    </>
  )
}

export default Header

 

  • src/assets/scss/common.scss

reset.scss, font.scss 등 공통적으로 필요한 scss 파일을 페이지마다 import 하면 번거롭고, 코드도 길어지기 때문에 common.scss를 만들어 한 개의 scss 파일에 작성되도록 한다.

// base
@import './base/reset';
@import './base/font';

// layout
@import './layout/layout';

 

  • src/App.tsx

최종적으로 common.scss를 App 컴포넌트에 import 한다.

import React from 'react'
import Layout from './components/layouts/Layout'
import './assets/scss/common.scss'

const App = () => {
  return (
    <Layout>
      <h1>내용을 작성해 주세요.</h1>
    </Layout>
  )
}

export default App

결과 화면

 


1. 레이아웃 컴포넌트 만들기

  • src/components/layouts/Header.tsx
const Header = () => {
  return (
    <>
      <header>헤더 컴포넌트입니다.</header>
    </>
  )
}

export default Header

 

  • src/components/layouts/Footer.tsx
const Footer = () => {
  return (
    <>
      <footer>푸터 컴포넌트입니다.</footer>
    </>
  )
}

export default Footer

 

  • src/components/layouts/Layout.tsx

헤더와 푸터는 페이지마다 공통으로 보여지는 영역이기 때문에 import 해서 사용하면 되지만,

메인의 컨텐츠 영역은 페이지마다 내용이 바뀌기 때문에 props로 사용한다.

import Header from './Header'
import Footer from './Footer'

const Layout = (props: {children: React.ReactNode}) => {
  return (
    <>
      <Header/>

      <main>{props.children}</main>

      <Footer/>
    </>
  )
}

export default Layout

 

2. index.tsx, App.tsx 수정하기

  • src/index.tsx

불필요한 소스를 삭제한다.

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
)

root.render(
  <React.StrictMode>
    <App/>
  </React.StrictMode>
)

 

  • src/App.tsx

레이아웃 컴포넌트를 import 한다.

<h1>의 내용이 <Layout> 컴포넌트의 <main> 태그 안에 들어가게 된다.

<Layout> 컴포넌트로 감싸 여러 페이지들을 만들면 된다.

import React from 'react'
import Layout from './components/layouts/Layout'
import './App.css'

const App = () => {
  return (
    <Layout>
      <h1>내용을 작성해 주세요.</h1>
    </Layout>
  )
}

export default App

1. Node.js 설치하기

https://nodejs.org/ko

Node.js는 Chrome V8 JavaScript 엔진으로 빌드된 JavaScript 런타임이다.

 

위의 정의는 노드를 통해서 자바스크립트 애플리케이션을 실행할 수 있다는 의미이다.

타입스크립트는 자바스크립트에 타입을 추가한 언어이기 때문에 타입스크립트를 사용하기 위해서는 Node.js를 먼저 설치해야 한다.

 

1-1. Node.js 버전 확인하기

node --version
또는
node -v

 

 

2. typescript, ts-node 글로벌 설치하기

typescript와 ts-node를 글로벌로 설치하면 리액트 프로젝트가 아니더라도 타입스크립트를 사용할 수 있기 때문에 따로 설치하는 것이 좋다.

또한 글로벌이기 때문에 1번만 설치하면 추가 설치 없이 바로 사용할 수 있다.

yarn add -g typescript ts-node
또는
npm install -g typescript ts-node

 

2-1. typescript, ts-node 버전 확인하기

tsc --version 또는 tsc -v

ts-node --version 또는 ts-node -v

 

 

3. 프로젝트 만들기

yarn create react-app 폴더명 --template typescript
또는
npx create-react-app 폴더명 --template typescript

 

tsx 파일이 생성됐는지 확인한다.

 

 

4. 불필요한 파일 삭제하기

src 폴더에서 App.css, App.tsx, index.css, index.tsx 파일만 남기고 전부 삭제한다.

 

5. 로컬호스트 연결 확인하기

http://localhost:3000/

터미널에서 yarn start 명령어를 실행해 로컬호스트에 접속이 잘 되는지 확인한다.

아래와 같은 화면이 나온다면 정상적으로 세팅이 완료된 것이다.

 

+ Recent posts