빈 폴더에 index.html 새파일 추가

 

필수 핵심

1. vue 라이브러리 cdn

<script src="https://unpkg.com/vue"></script>

2. 정의한 app 마운트 위치 잡기

Vue.createApp(Counter).mount('#counter');

 

전체예시 코드

#index.html
<!DOCTYPE html>
<html>
  <head>
    <title>Example 02</title>
  </head>
  <body>
    <div id="counter">
      <div>Counter : <span v-text="count"></span></div>
      <div>DoubleCounter : {{ count * 2 }}</div>
      <button v-on:click="increase">up</button>
      <button @click="decrease">down</button>
    </div>
  </body>
   <script src="https://unpkg.com/vue"></script>
    <script>
      const Counter = {
        data() {
          return {
            count: 0,
          };
        },
        methods: {
          increase() {
            this.count++;
          },
          decrease() {
            this.count--;
          },
        },
      };
      Vue.createApp(Counter).mount('#counter');
    </script>
</html>

실행결과

자바스크립트 엔진의 구조

  • Heap : 메모리 할당을 담당
  • Stack : 1개의 stack = single Thread = 동기적 실행, 호출된 시점에 Stack 이 쌓인다. 실제 업무 수행 담당
  • Web API : 비동기적 task를 수행하는 곳, 비동기적 task 예시) setTimeout, AJAX, 이벤트리스터, Promise.then
  • Callback Queue : 비동기 task 다 끝나면 들어가는 곳, microtask Q > animation Frame Q > task Q(event Q) 세가지의 Q가 내부에 존재하고, 순서대로 우선순위를 갖는다.
  • Event Loop : Stack 의 상태를 계속 주시하다가, 비어있는 순간 콜백큐의 task를 stack으로 집어넣어준다.

[실행 코드 예시]

console.log("A");

setTimeout(function(){
	console.log("setTimeout")
}, 0);

Promise.resolve()
	.then(function() {
    console.log("Promise");
   }
);

// 엄청 오래걸리는 작업이라고 가정
console.log("B");

 

1. 먼저 동기적 작업이 Stack에 쌓이고, 바로 실행된다.

 

2. setTimeout이라는 비동기 작업은 WebAPI 에서 수행이 된다.

 

3. 다음 비동기 작업인 Promise.then이 WebAPI 로 가서 수행된다.

 

4. 다음 동기 작업인 console.log("B") 가 Stack 에 쌓이고 바로 실행된다 (여기서 이 동기작업은 매우 오래걸리는 작업으로 가정했다: 계속 실행되고 있는 중임)

 

5.  비동기작업 중에 setTimeout이 먼저 끝났다고 가정했다. setTimeout 은 콜백 큐에서 가장 우선순위가 낮은 Task Queue로 들어간다. (JS자체에서 정해놓은 룰임)

 

6. 다음으로 끝난 Promise.then 이 콜백큐에서 가장 순위가 높은 microtask queue로 들어간다. (이 역시 JS 자체의 룰)

 

7.  드디어 동기작업인 console.log("B") 가 끝났다. console("B") 가 끝나지 않으면 콜백큐에 대기중인 작업들은 수행될 수 없다.

 

8. 비동기 작업들 중에 setTimeout이 먼저 끝났지만, 우선순위에 의해 Promise가 먼저 stack으로 올라간다. (이벤트 루프가 올린다), 바로 실행된다.

 

9. stack이 비면, 이벤트루프가 마지막 setTimeout 을 stack으로 올리고, 실행된다.

 

HTML5에서 웹의 데이터를 저장할 자료구조 공간 스토리지 스펙을 제공한다.

그 공간은 키 : 밸류 쌍으로 데이터를 저장하고 키값을 통해 데이터에 접근할 수 있다.

이 웹스토리지에 포함되는 것이 바로 로컬스토리지와 세션스토리지 이다.

 

쿠키는 고인물이고, 웹스토리지가 5부터 등장

 

쿠키 대비 웹스토리지의 장점

 

1. 쿠키는 매번 서버로 전송됨

웹스토리지 저장된 데이터는 그냥 클라이언트에 존재, 서버로 전송은 자동으로는 이루어지지 않음

트래픽 비용 절감

 

2. 단순 문자열을 넘어 객체정보를 저장가능

브라우저의 지원여부는 확인 필요

 

3. 용량의 제한 없음

쿠키는 최대 4KB, 20개까지 한 사이트에서 저장 가능

모바일은 2.5mb, 데스크탑은 5mb-10mb

 

4. 영구저장가능

쿠키는 만료일자를 지정하게 되어 언젠가 제거된다. -> 다시보지않음 팝업창은 쿠키에 저장

 

 

로컬스토리지와 세션스토리지

 

로컬스토리지

저장한 데이터를 명시적으로 지우지 않는 이상 영구적 보관가능

브라우저를 종료해도 다음번 접속에도 그 데이터를 사용가능

지속적으로 필요한 데이터(자동로그인)은 로컬스토리지에 저장

 

세션스토리지

데이터가 지속적으로 보관되지 않는다.

브라우저를 종료하면 데이터도 같이 지워진다.

탭 브라우징(동일 도메인을 탭추가하여 접속) 해도 로그인 새로 해야함

잠깐 필요한 데이터는 세션스토리지(일회성 로그인/입력 폼 정보/ 비로그인 장바구니)

 

 

 

'programming > Web' 카테고리의 다른 글

[AWS] IAM 이란? (개념과 실습)  (0) 2022.04.05
API, SDK, Library, Framework  (0) 2022.03.10
CSS3 특성 선택자(Selector)  (0) 2022.03.05
REST Service에 대하여  (0) 2022.03.05
HTTP 헤더 총정리  (0) 2022.03.04

여러가지 정의들 중에, 개인적으로 좀 더 직관적으로 받아들여 졌던 정의는, 다음과 같다

클로저란, 생성한 시점의 스코프체인을 기억하여, 비공개 변수를 가질수 있는 환경에 있는 함수이다.

 

이 외, 다른 정의들

  • MDN) 클로저는 독립적인 변수를 가리키는 함수이다. 또는 클로저 안에 정의된 함수는 만들어진 환경을 기억한다.
  • 함수와 렉시컬 환경의 조합
  • 함수가 생성될 당시의 외부변수를 기억하여 생성 이후에도 계속 참조가 가능한 것
  • 생성한 시점의 스코프체인을 계속 들고있는 함수

 

 

 

일단 실무에서는 private 변수를 사용하기 위한 것으로 많이 쓰인다.

 

 

선행지식 스코프체인

 

스코프는 일단 범위라는 뜻인데, 간단하게 브라켓{}, 블록 안 저장소라고 생각하자.

 

블록별로 (if문, 함수선언문, while...등) 자기만의 스코프를 갖는것이다.

 

근데 이게 전역 안에 외부함수 안에 내부함수 안에 내부함수 .... 이런식으로 함수안의 함수를 알낳기를 계속하면,

 

내부의 브라켓(함수)부터 상위의 스코프를 참조할 수 있다.

 

체인처럼 이어서 참조할 수 있다는 것을 스코프 체인이라 한다.

 

다시 클로저로 돌아와서,

 

클로저는 이 스코프 체인의 특성을 이용하면서 블록안의 변수를 블록 밖에서도 사용할 수 있게한다.

하지만 매우 제한적인 조건으로

 

여기서 제한적인 조건이 나오는데, 내부의 변수나 메소드들을 지정하고 외부에서 끌어쓸때 함부로 내부의 내용들을 변경할 수 없게 만든다.

그런맥락에서 이름이 클로저가 아닐까 싶다.

 

function makeCounter() {
    let num = 0;

    return function() {
        return num++
    }
}

let counting = makeCounter();

console.log(counting())  // 0
console.log(counting())  // 1
console.log(counting())  // 2
console.log(counting.num)  // undefined

 

var만 쓰고 있다가 ES6에서 let과 const가 추가됨

 

var & let 중복선언 관점에서의 차이점

var은 중복선언이 가능하다. let은 중복선언이 불가능하다. 둘다 재할당은 가능(당연한 소리)

 

case1) var은 재할당, 중복선언 모두 가능하다. --> 이상한것..

var gender = 'female'
console.log(gender)

// 변수 재할당 가능
gender = 'none'
console.log(gender)

// 변수 중복 선언 가능
var gender = 'male'
console.log(gender)

 

case2) let은 재할당은 가능하나 중복선언이 불가하다. -> 당연한것..

let name = 'Mike'
console.log(name) // output: Mike

// 변수 재할당 가능
name = 'Heidy'
console.log(name) // output: Heidy

// 변수 중복선언 불가
let name = 'Sally' // output: Uncaught SyntaxError: Identifier 'name' has already been declared

 

case3) const 는 상수라서, 재할당 불가, 중복선언도 불가

// 원시값의 재할당
const name = 'kmj'
name = 'howdy' // output: Uncaught TypeError: Assignment to constant variable.

// 객체의 재할당
const name = {
  eng: 'kmj',
}
name.eng = 'howdy'

console.log(name) // output: { eng: "howdy" }

var & let 호이스팅 관점에서의 차이점

자바스크립트 엔진은 선언문(변수선언, 함수선언)을 찾아내 먼저 실행한다 -> 호이스팅

var과 let은 둘다 호이스팅 된다.

하지만 var은 할당이 되지 않았을 때도, undefined라고 자체적으로 초기값을 넣어서 에러를 발생시키지 않는다.

let은 할당되지 않았을 경우, 초기값이 없다는 에러를 발생시킨다.

 

case1) a를 선언하지 않고 부르면 당연히 에러발생

console.log(a)

 

case2) a를 선언하고 부르면 당연히 잘 불려짐

var a = "apple"
console.log(a)

 

case3) a를 부르고, 선언하면? 에러는 안났는데, 할당이 안된것

-> 호이스팅 (선언+undefined라고 초기화)

console.log(a)
var a = "apple"

 

case4) 그럼 let으로 a 를 선언했을 경우는? 에러난다

console.log(a)
let a = "apple"

 

변수 뿐아니라 var, let, const, function, function*, class 의 키워드를 사용한 선언문은 모두 호이스팅 된다.

 

var & let 스코프 관점에서의 차이점

var은 함수만 지역스코프로 인정되어 지역변수로 처리된다.

let은 모든 브라켓표현식을 지역스코프로 인정하여 지역변수 처리한다.

 

case1) var는 function 브라켓(스코프) 안에서는 지역변수로 작동한다.

var a = 1; // 전역변수

function test() {
    var b = 2; // 지역변수
}

console.log(a) 
console.log(b) // 함수브라켓은 지역변수로 작동하여, 밖에서 호출시 에러

 

case2) function 이 아닌 다른 브라켓(스코프) , for, while, if, switch...등 안에서는 지역변수로 처리되지 않는다.

var a = 1;

while(true){
    var b = 5;
    break
}

console.log(a)
console.log(b)

 

case3) let은 모든 브라켓(스코프)안에서 선언된 변수들은 모두 지역변수로 처리한다

var a = 1;

while(true){
    let b = 5;
    break
}

console.log(a)
console.log(b) // 지역스코프 밖에서 호출시 에러

1. JDK 설치

: x64 Compressed Archive zip 파일 다운로드

 

https://www.oracle.com/java/technologies/downloads/#jdk17-windows

 

2. 이클립스 설치

: Eclipse IDE for Enterprise Java and Web Developers (Windows x86_64) 다운로드

 

https://www.eclipse.org/downloads/packages/

 

Eclipse Packages | The Eclipse Foundation - home to a global community, the Eclipse IDE, Jakarta EE and over 350 open source pro

509 MB 566,255 DOWNLOADS Tools for developers working with Java and Web applications, including a Java IDE, tools for JavaScript, TypeScript, JavaServer Pages and Faces, Yaml, Markdown, Web Services, JPA and Data Tools, Maven and Gradle, Git, and more. Cli

www.eclipse.org

 

3. 데이터베이스 설치

: 메모리 DB

: JAVA 로 만들어진 RDB

: 오라클이나 mysql처럼 설치과정이 복잡하지 않고, zip 파일을 압축만 풀면 간단하게 설치가능

: All platfom 용으로 다운로드

 

https://h2database.com/html/main.html

 

H2 Database Engine

H2 Database Engine Welcome to H2, the Java SQL database. The main features of H2 are: Very fast, open source, JDBC API Embedded and server modes; in-memory databases Browser based Console application Small footprint: around 2.5 MB jar file size     Supp

h2database.com

 

4. 톰캣(Tomcat)

: 9버전 64-bit Windows.zip 다운로드

 

https://tomcat.apache.org/download-90.cgi

 

Apache Tomcat® - Apache Tomcat 9 Software Downloads

Welcome to the Apache Tomcat® 9.x software download page. This page provides download links for obtaining the latest version of Tomcat 9.0.x software, as well as links to the archives of older releases. Unsure which version you need? Specification version

tomcat.apache.org

 

 

 

5. 압축해제 후 폴더 구조

: C밑에 원하는 이름으로 폴더를 만들고, jdk 압축해제 한 내부 파일을 이동시킨다.

: workspace도 별도로 생성한 파일

 

 

6. 환경변수 설정

: 시스템변수 신규 추가 JAVA_HOME

: 시스템변수 Path 에 %JAVA_HOME%\bin 추가

 

7. 설정 및 버전 확인

: cmd 창에 java -version 확인

 

TypeError [ERR_UNESCAPED_CHARACTERS]: Request path contains unescaped characters

 

일단 상황은 해시태그를 url 에 담아서 서버로 get 요청을 하는 것이다.

 

해시태그는 당연히 한글이 될 수 있다.

 

프론트 서버에서는 다음과 같은 에러를 뱉어냈다.

 

 

에러발생의 원인인 axios 로 서버에 API 요청을 하는 부분을 보자

 

axios.get(`/hashtag/${data}?lastId=${lastId || 0}`);

 

data 변수에 hashtag 가 들어간다.

 

lastId 는 페이지네이션을 위한 것이므로 여기서는 무시한다.

 

data 에 한글이 들어갈경우 백엔드로 요청하는 API는 '/hashtag/크리스마스' 가 되는 것이다.

 

여기서 바로 에러가 발생한 것이다.

 

그럼 해결책은?

 

바로 enCodeURIComponent & deCodeURIComponent 를 사용하여 한글을 처리해주면 된다.

 

먼저, 브라우저 콘솔창에서 enCodeURIComponent & deCodeURIComponent 를 실행해보자

 

다음과 같이 인코딩/디코딩 되는 것을 확인할 수 있다.

 

이를 활용하여 한글 해시태그를 처리해주자.

 

1. 프론트 측 : enCodeURIComponent 를 사용하여 한글을 인코딩

axios.get(`/hashtag/${encodeURIComponent(data)}?lastId=${lastId || 0}`);

 

2. 백엔드 측 : 받은 변수를 deCodeURIComponent 를 사용하여 디코딩

include: [{
            model : Hashtag,
            where : { name : decodeURIComponent(req.params.hashtag)} //해시태그 조건
          }

 

(1) TextField

https://tacit.tistory.com/41

 

react-hook-form 과 meterial-UI 함께 쓰기 (1) - TextField

react-hook-form은 material-UI 나 ant-D같은 외부 UI 라이브러리와 함께 사용할 수 있다. 그 중 가장 기본이 되는 TextField와 연결하는 방법을 정리해보려한다. import TextField from '@material-ui/core/TextF..

tacit.tistory.com

(2) ToggleButton

https://tacit.tistory.com/42

 

react-hook-form 과 meterial-UI 함께 쓰기 (2) - ToggleButton

이전 게시물(1) - TextField 에 이어서 이번엔 ToggleButton 과 함께 사용하는 방법에 대해 정리해보려한다. CheckBox로 예시들이 몇개 구글에 나와있다. ToggleButton도 비슷한 맥락이다. import ToggleButton fr..

tacit.tistory.com

 

 

이어서 2개의 datePicker를 조합하여 만든 dateRangePicker 를 react-hook-form 과 연결하는 방법에 대해서 정리해보려 한다.

 

우선 구현하고자 하는 것은 다음과 같다.

기간을 입력받은 range Picker  이다.

 

서버로 보내야하는 데이터는 다음과 같이 시작일 / 종료일을 보내는 것이다.

formData : {
'startDatetime' : 2022-01-30
'endDatetime' : 2022-01-30
}

 

우선 이 DateRangePicker 는 재사용할 것이므로 js파일로 따로 만들어져 있고, 부모 컴포넌트에서 import 받아서 사용한다.

 

1. 부모 컴포넌트

 

import DateRangePickerCustom from './DateRangePickerCustom';
import { useForm } from 'react-hook-form';

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

  const initialDate = {
    startDate : new Date(),
    endDate : new Date()
  }
  
  const onSubmit = (data) => {
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div className="modal-title">진행기간</div>
      <DateRangePickerCustom
        initialDate={initialDate}
        control={control}
        watch={watch}
      />
      <button type="submit">전송</button>
    </form>
  );
}

 

상단의 DateRangePickerCustom 으로 컴포넌트를 받아와서 사용한다.

 

이전의 TextField / ToggleButton 과는 확연히 다른 포맷이다.

1. 가장먼저 눈에 띄는 것은 UI 컴포넌트를 감싸서 사용하던 <Controller> 가 사라졌다!

2. initialDate 를 지정하여 <DateRangePickerCustom>으로 전달한다.

3. control 을 props 로 전달한다.

4. 처음 보는 watch 라는 것을 useForm에서 추가로 선언하고, props 로 전달한다.

 

그럼 이 차이점들에 대해서 하나씩 살펴보자.

 

먼저 DateRangePickerCustom.js 파일의 코드를 보면

(react-datepicker 라이브러리를 사용하엿다. https://www.npmjs.com/package/react-datepicker)

 

react-datepicker

A simple and reusable datepicker component for React

www.npmjs.com

 

import React from "react";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css"
import { ko } from 'date-fns/esm/locale';
import { Controller } from 'react-hook-form';

function DateRangePickerCustom({initialDate, control, watch}) {
  console.log("control", control)
  console.log('watch', watch("startDatetime"))
 
    return (
      <>
      <div className="date-picker-wrapper">
        <Controller
          control={control}
          name="startDatetime"
          defaultValue={initialDate.startDate}
          render={({ field }) => (
            <DatePicker
              className="date-picker"
              selected={field.value}
              onChange={(date) => {
                field.onChange(date)
                console.log('field.startDatetime', field)
              }}
              selectsStart
              startDate={watch("startDatetime")}
              endDate={watch("endDatetime")}
              locale={ko}
              dateFormat="yyyy년 MM월 dd일"
            />
          )}
        />
        <div className="date-span">-</div>
        <Controller
          control={control}
          name="endDatetime"
          defaultValue={initialDate.endDate}
          render={({field}) => (
            <DatePicker
              className="date-picker"
              selected={field.value}
              onChange={(date) => {
                field.onChange(date)} 
              }
              selectsEnd
              startDate={watch("startDatetime")}
              endDate={watch("endDatetime")}
              minDate={watch("startDatetime")}
              locale={ko}
              dateFormat="yyyy년 MM월 dd일"
            />
          )}
        />
      </div>
      </>
    );
  };


  export default DateRangePickerCustom;

 

 

부모 컴포넌트에서 전달받은 initialDate, control, watch 를 받고있다.

 

1. Controller 는 name을 갖게될 하나하나의 필드값에 적용해야한다. 그러므로 부모컴포넌트에서가 아닌 자식 컴포넌트에 지정을 해야한다.

부모 컴포넌트에서는 react-hook-form과 mui를 연결해줄 control 값만 받아오고, Controller는 자식컴포넌트에서 import 하여 startDate를 위해 감싸주고, endDate를 위해 감싸주는 것처럼 각각의 필드값을 각각 감싸주는 것이다.

 

2. initialDate는 defaultValue를 지정하기 위해서 부모 컴포넌트에서 받아주었다. 

이는 다른 부모 컴포넌트들에서는 다른 initialDate를 사용하기 때문에 자식 컴포넌트에 직접 defaultValue에 적지 않았다. 무조건 new Date() 라는 값을 defaultValue 로 사용할 거라면 initialDate를 전달받지 말고 자식 컴포넌트에 바로 적어주어도 된다.

 

3. 부모로 부터 전달받은 control을 console.log로 찍어봤다.

그냥 react-hook-form 과 연결하기 위한 여러가지 값들이라고 생각하고 넘어가자...ㅎ

 

4. 이제 watch 에 대해서 알아보자.

watch는 react-hook-form 에서 제공한다.

말그대로 해당 필드의 값을 계속 지켜보겠다는 것 이다.

watch("startDatetime") 을 console.log로 찍어보았다.

시작일 값이 변경될 때마다 변경된 Date 값을 찍어준다.

 

우리의 dateRangePicker 는 시작일과, 종료일이 서로 연관되어있다. 기간의 개념으로, 종료일은 시작일보다 빠를 수 없다.

이에 대한 설정 값이 

시작일 의 경우

종료일의 경우 

여기서 기간에 대한 개념을 구현하기 위해서는 서로 다른 필드값 (startDatetime / endDatetime) 을 참조해야하는 것이다.

 

그러므로 서로 다른 필드값을 참조할 수 있든 watch를 사용한 것이다.

 

 

이전 게시물(1) - TextField 에 이어서

https://tacit.tistory.com/41

 

react-hook-form 과 meterial-UI 함께 쓰기 (1) - TextField

react-hook-form은 material-UI 나 ant-D같은 외부 UI 라이브러리와 함께 사용할 수 있다. 그 중 가장 기본이 되는 TextField와 연결하는 방법을 정리해보려한다. import TextField from '@material-ui/core/TextF..

tacit.tistory.com

 

이번엔 ToggleButton 과 함께 사용하는 방법에 대해 정리해보려한다.

 

CheckBox로 예시들이 몇개 구글에 나와있다.

 

ToggleButton도 비슷한 맥락이다.

 

import ToggleButton from '@mui/material/ToggleButton';
import { BiLock } from "react-icons/bi";
import { useForm, Controller } from 'react-hook-form';

export default function App() {
  const { handleSubmit, control, formState: {errors} } = useForm();

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

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        name="shareState"
        control={control}
        defaultValue={false}
        render={({ field }) => (
          <>
            <div className="modal-title">{field.value? "비공개":"공개"}</div>
            <ToggleButton
              color="primary"
              value="check"
              selected={field.value}
              onChange={() => field.onChange(!field.value)}
            >
              <BiLock className="lock-icon"/>
            </ToggleButton>
          </>
        )}/>
      <button type="submit">전송</button>
    </form>
  );
}

 

일단 포멧은 1편의 TextField와 동일하다.

 

controller를 import 한 뒤 , 원하는 UI 컴포넌트를 <Controller> 컴포넌트로 감싸주면 된다.

 

여기서 핵심적으로 다른 부분은 바로 onChange 속성을 사용하는 것이다.

 

우선 1편과 동일하게 전달해주는 속성들에 대해서 간략하게 정리해보자

 

  • name : 역시 form 제출시 key 값으로 사용될 값이다. 이 경우 게시글을 공개할껀지, 비공개로 할 것인지를 정하는 shareStatus라는 키값으로 표현했다.
    서버로 제출시 "shareStatus" : false 이런식으로 제출될 예정!
  • control : react-hook-form과 material-UI를 연결해주는 용도라고 생각하고 넘어가자
  • defaultValue : 역시 1편에서 설명했듯이, 지정하지 않으면 쓸 데없는 warning이 발생한다.
index.js:1 Warning: A component is changing an uncontrolled input to be controlled.
This is likely caused by the value changing from undefined to a defined value, which should not happen.
Decide between using a controlled or uncontrolled input element for the lifetime of the component.
More info: https://reactjs.org/link/controlled-components

 

  • render : 내가 쓰고 싶은 UI의 컴포넌트를 적어주면 되는 부분이다.
    • field : form에 제출하는 value와 관련된 내용을 이어준다? 라고 생각해보자
    • 일단, 나의 경우 shareStatus 값에 따라서 위의 타이틀이 공개 <-> 비공개 토클이 되어야 해서 위와 같이 삼항연산자로 표현해 주었다
      상단의 타이틀 토글
    • ToggleButton 컴포넌트를 랜더링해준다. ToggleButton 컴포넌트의 경우 mui에서 제공하는 도큐먼트에 따르면,
      • value = 'check' 라는 props를 통해서 checkbox 처럼 true/false 값으로 사용할 수 있다.
      • selected 속성은 field.value를 통해서 react-hook-form이 읽어갈 value 값과 연결을 해준다.
      • onChange 속성은 mui에서 제공하는 props인데, 이제 이를 react-hook-form 의 onChange와 연결을 해주어야 한다. 그 방법은 위에 code와 같다.
        field 객체 안의 onChange 함수를 실행시키면서, field.value의 값을 ! 로 토글 시키는 것이다 (true<->false)

 

 

다음 게시글에서는 <TextField> , <ToggleButton> 처럼 단일 컴포넌트를 받아서 쓰는 것이 아닌, 여러가지 컴포넌트들을 조합하여 커스텀한 컴포넌트 그룹을 react-hook-form 과 연결하는 방법에 대해 정리해 보려 한다.

 

https://tacit.tistory.com/43

 

react-hook-form 과 meterial-UI 함께 쓰기 (3) - DateRangePicker

(1) TextField https://tacit.tistory.com/41 react-hook-form 과 meterial-UI 함께 쓰기 (1) - TextField react-hook-form은 material-UI 나 ant-D같은 외부 UI 라이브러리와 함께 사용할 수 있다. 그 중 가장 기..

tacit.tistory.com

 

react-hook-form은 material-UI 나 ant-D같은 외부 UI 라이브러리와 함께 사용할 수 있다.

 

그 중 가장 기본이 되는 TextField와 연결하는 방법을 정리해보려한다.

 

import TextField from '@material-ui/core/TextField';
import { useForm, Controller } from 'react-hook-form';

export default function App() {
  const { handleSubmit, control, formState: {errors} } = useForm();

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

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller 
        name="title" 
        control={control}
        defaultValue=""
        render={({ field }) => (
        <TextField
          {...field}
          id="title" 
          label="제목" 
          size="small" 
          variant="outlined"
          style={{width:"100%", marginBottom:"10px"}}
          InputLabelProps={{
            shrink: true,
          }}
          error={!!errors.title}
          helperText={errors.title ? errors.title?.message : ''}
        />
        )}/>
      <button type="submit">전송</button>
    </form>
  );
}

 

전달하는 속성들에 대해서 간략하게 정리해보자면

 

  • name : react-hook-form이 작성된 폼의 값들을 모아서 제출할 때, key 값으로 사용할 값이다. 유니크한 값으로 지정하도록 한다.
  • control : 상단의 useForm() 에서 선언한 control 인데, 간단하게 react-hook-form과 mui를 이어주는 용도라고 생각하자
  • defaultValue : 말 그대로 초기값인데, 없다면 빈스트링이라도 지정해두자. 지정하지 않으면 다음과 같은 warning 이 발생한다
index.js:1 Warning: A component is changing an uncontrolled input to be controlled. 
This is likely caused by the value changing from undefined to a defined value, which should not happen. 
Decide between using a controlled or uncontrolled input element for the lifetime of the component. 
More info: https://reactjs.org/link/controlled-components

 

  • render : 이제 내가 쓰고 싶은 UI 컴포넌트를 어떤식으로 렌더링 하겠다고, react-hook-form 에게 알려주는 부분이다다. 
    이 부분에서 원하는 컴포넌트를 (TextField)를 사용하면된다. TextField 컴포넌트 내부의 props들은 그냥 material-UI에서 제공하는 내용을 원하는대로 가져다 쓰면된다. 
    • error : mui 에서 기본적으로 제공하는 prop이지만 이를 react-hook-form에서 제공하는 validation 과 errors를 받아서 사용할 수 있다.
    • helperText : 역시 react-hook-form에서 던져주는 에러메시지를 받아서 사용할 수 있다.
      (기본적으로 영문 메시지가 뜨는데, 아래의 경우는 yup이라는 validation check용 라이브러리를 사용하여 에러메시지를 지정해준 경우이다.)

 

TextField의 경우 onChange 등 별도로 지정해 줄게 따로 없어서 간단하다.

 

다음 게시물(2)에서는 onChange 속성을 사용하는 ToggleButton에 대해서 알아보려한다.

https://tacit.tistory.com/42

 

react-hook-form 과 meterial-UI 함께 쓰기 (2) - ToggleButton

이전 게시물(1) - TextField 에 이어서 이번엔 ToggleButton 과 함께 사용하는 방법에 대해 정리해보려한다. CheckBox로 예시들이 몇개 구글에 나와있다. ToggleButton도 비슷한 맥락이다. import ToggleButton fr..

tacit.tistory.com

 

+ Recent posts