[Vue] Vue시작(1) - React와 비교, CDN으로 간단한 프로젝트 따라하기

권준혁·2020년 12월 5일
1

vue

목록 보기
1/8
post-thumbnail

특징

Vue는 사용자 인터페이스를 만들기 위한 프로그레시브 프레임워크다. (점진적으로 적용가능한 프레임워크다)
React는 UI라이브러리다.

다른 단일형 프레임워크와 달리 Vue는 점진적으로 채택할 수 있도록 설계됐다.
핵심 라이브러리는 뷰 레이어만 초점을 맞추어 다른 라이브러리나 기존 프로젝트와의 통합이 매우 쉽다.

React와 Vue

Vue와 다른 프레임워크와 비교

번들러

React와 Vue모두 번들러로 Webpack을 사용할 수 있다.

재사용성과 업데이트

이 것은 React에서 컴포넌트를 재사용 가능하도록 나누되, css-in-js스타일로 CSS를 구성하는 것과 같은 의미를 가진다.
이렇게 하면 컴포넌트의 응집력유지보수성 이 향상된다.
CSS, JS, HTML의 거대한 레이어로 나누는 대신 느슨하게 결합된 컴포넌트로 나누고 구성하는 것이 더 중요하다.
하나의 컴포넌트를 만들기 위해서 CSS폴더, JS폴더, HTML폴더를 왔다 갔다 해야 한다면 응집력이 낮아 유지보수성이 떨어지는 경우에 해당한다.

Vue와 React는 모두 가상돔을 사용하고 비교하여 컴포넌트를 업데이트하지만,
리액트는 state나 props가 변경되면 하위 컴포넌트를 기본적으로 모두 업데이트하고, (PureComponent로 작성되거나, shouldComponentUpdate에서 업데이트를 제한한 경우를 제외하고 업데이트)
Vues는 실제로 다시 렌더링해야 하는 컴포넌트를 정확히 렌더링한다는 장점이 있다.

HTML & CSS

React에서는 JSX를 사용한다. Javascript 과 XML이 합쳐진 문법이다. XML유사한 형태로 사용할 수 있게 해주고, 컴파일 시 React.createElement함수로 변환된다. 여기에 css-in-js형태로 css를 작성하면 JS만으로 컴포넌트를 작성할 수 있게 된다.

Vue는 고전적인 웹기술(HTML, CSS)를 받아들여서 그 기반위에 만들어졌다.
Vue는 Template이라는 것을 사용하는데, 기존의 HTML에 약간의 템플릿 문법 (예: v-on 등)이 추가된 것이다.

컴포넌트는 표현형과 논리형 두 가지로 나눌 수 있는데, 대부분의 경우 표현형이다.
Vue의 템플릿은 표현형에, 렌더링함수와 JSX는 논리형에 사용하는 것이 좋다. 그리고 대부분의 컴포넌트는 표현형이 더 많다.
또 중요한 점은 Vue에서도 JSX를 사용할 수 있다는 것이다.

css-in-js사용 하는 것은 일반적인 css작성 프로세스와 다른 컴포넌트 지향 패러다임을 뜻한다. 컴포넌트의 응집력을 높히고 결합을 느슨하게해서 재사용성을 늘리는 것을 말한다.
webpack등을 통해 빌드타임에 단일 스타일 시트로 css를 추출할 수 있기도 하지만, 코드 변화에 다른 스타일이 제대로 작동하려면 번들에 포함되어야 한다.
이 것은 JS를 통해서 역동적인 기능을 사용할 수 있지만 증가한 번들 크기 및 런타임 비용에 따라 성능상 문제가 생길 수도 있다.

뿐만아니라 styled-component-vue나 emotion-vue같은 css-in-js 대표적인 라이브러리들이 Vue를 지원한다.

하지만, 기본적인 css사용법 부터 살펴보자
vue컴포넌트는 기본적으로 vue라는 이름의 확장자를 갖는다.
이 싱글파일 컴포넌트를 통해서 css에 접근할 수 있다.
vue-loader CSS전처리기, style태그 사용법

이 싱글파일 컴포넌트 내에서 style태그를 통해 css에 접근할 수 있다.
아래 링크에서 Vue파일을 열어보면 크게 세 가지로 나뉘어 있는 것을 볼 수 있다.
template script style
style태그에 scoped를 추가하면 선택자에 해시값을 추가해서 scoped된 상태로 사용할 수 있다. 쉽게 말하면 다른 파일에서 중복된 클래스명,아이디명을 사용할 수 있기 때문에 불필요하게 고민할 필요가 없어진다.

React와 Vue의 기타 라이브러리

또 다른 중요한 차이점은 상태 관리 및 라우팅을 위한 Vue의 기타 라이브러리 (기타 관심사 중)는 모두 공식적으로 지원되며 핵심 라이브러리와 함께 최신 상태로 유지된다는 것입니다. 반대로 React는 커뮤니티에 이러한 결정을 맡기고 더 분열 된 생태계를 만드는 것을 선택했습니다. 그 결과 React의 생태계는 Vue보다 훨씬 풍부합니다.

Vue 공식 깃허브

React관련 라이브러리들을 npm에서 검색하면 훨씬 많고 다양한 결과를 볼 수 있다. 결론은 React는 생태계가 더 크고 풍부하다. Vue는 자체적으로 관리하기 때문에 핵심 라이브러리들과 함께 최신버전으로 유지가 되기 때문에 고민할 필요가 별로 없다는 점이 장점이 될 수 있다.

라이프사이클

Router

Vue로 만들어진 todo app, 코드샌드박스, Vue튜토리얼에서 제공

기타 지원 라이브러리

Vue에서 사용하는 라이브러리 모음

도움 될 만한 것들, 참고

Vue 공식 깃허브

Vue 한글문서

Vue CLI 설치, 공식문서

Vue 무료 강의 동영상 [영어]

Vuejs 튜토리얼 scrimba.com1
Vuejs 튜토리얼 scrimba.com2

Vue Plugin과 Preset

vue-loader CSS전처리기

김정환님 블로그


시작하기 vue-cli

Vue Cli를 설치하고 vue create 프로젝트를 입력하면 프로젝트 생성 옵션을 선택하는 커맨드가 나온다.

먼저 CDN방식으로 기본사용법을 익히고 vue-cli를 이용해서 작은 프로젝트를 해봐야겠다.


튜토리얼은 조현영님 Vue무료강의를 따라 작성했습니다.

시작하기 cdn

1. 좋아요

html에 태그를 추가하는 것 만으로도 간단하게 시작할 수 있다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>좋아요</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="root">
        <div v-if="liked"> 좋아요 눌렀음 </div>
        <button v-else v-on:click="onClickButton">Like</button>
    </div>
</body>
<script>
    const app = new Vue({
        el: '#root',
        data: {
            liked: false,
        },
        methods: {
            onClickButton() {
                this.liked = true;
            }
        }
    });
</script>
</html>

스크립트에서 new Vue 부분을 보면, el은 Vue가 컨트롤할 element를 나타내고, data는 컴포넌트에서 사용할 데이터, methods는 이벤트 함수를 작성한다.

html에서는 v-if v-else v-else-if 등 다양한 템플릿 문법을 사용할 수 있는데 직관적이라서 알기 쉽다.
v-if="liked"는 Vue객체의 data속성에서 liked를 나타낸다.

2. 가위바위보

v-model, IME이슈 해결방법

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="root">
        <div> {{first}} 곱하기 {{second}} 는? </div>
        <form v-on:submit="onSubmitForm">
            <input type="number" ref="answer" v-model="value">
            <button> 입력 </button>
            <div>{{ result }}</div>
        </form>
    </div>
    <script>
        const app = new Vue({
            el: '#root',
            data: {
                first: Math.ceil(Math.random() * 9),
                second: Math.ceil(Math.random() * 9),
                value: '',
                result: ''
            },
            methods: {
                onSubmitForm(e) {
                    e.preventDefault();
                    console.log(this);
                    console.log(this.first, this.second, this.value);
                    if (this.first * this.second == this.value) {
                        this.result = "정답";
                        this.first = Math.ceil(Math.random() * 9);
                        this.second= Math.ceil(Math.random() * 9);
                        this.value = "";
                        this.$refs.answer.focus();
                    } else {
                        this.result = "땡";
                        this.value= "";
                    }
                },
            },
        })
    </script>
</body>
</html>

먼저 this는 Vue객체를 나타낸다. this를 콘솔에 찍어보면 el,data,methods 에서 작성한 속성이 포함된 Vue객체가 출력된다.

this.first , this.second, this.result 로 data에 접근할 수 있다.
ref를 이용해서 돔 요소에 접근 할 수 있는데, React에서와 마찬가지로 DOM을 직접 조작하는 것은 지양해야 한다.
ref속성을 지정한 element는 this.$refs 를 통해 접근 할 수 있다. 꼭 필요한 경우에만 사용해야겠다.

또 한가지
v-model은 데이터의 값이 자동으로 해당 element에 연결되는 것인데,
React에서는 input의 value속성에 state값을 넣고, onChange에 setState를 했었던 것과 같다.

Vue에서 v-model이 없이 이 기능을 사용한다면 input태그에 v-on:input으로 이벤트 함수를 연결하고 v-bind:valuedata.inputText를 해야한다.

원래는 아래처럼 작성 해야 하는 것인데 자주 사용하게되는 패턴이기 때문에 편의성을 위해 제공하는 문법이다.

<body>
    <div id="root">
        <div> {{first}} 곱하기 {{second}} 는? </div>
        <form v-on:submit="onSubmitForm">
            <input type="number" ref="answer" v-bind:value="inputText" v-on:input="updateInput">
            <button> 입력 </button>
            <div>{{ result }}</div>
        </form>
    </div>
    <script>
        const app = new Vue({
            el: '#root',
            data: {
                first: Math.ceil(Math.random() * 9),
                second: Math.ceil(Math.random() * 9),
                value: '',
                result: '',
                inputText: ""
            },
            methods: {
                onSubmitForm(e) {
                    e.preventDefault();
                    console.log(this);
                    console.log(this.first, this.second, this.inputText);
                    if (this.first * this.second == this.inputText) {
                        this.result = "정답";
                        this.first = Math.ceil(Math.random() * 9);
                        this.second= Math.ceil(Math.random() * 9);
                        this.inputText = "";
                        this.$refs.answer.focus();
                    } else {
                        this.result = "땡";
                        this.inputText= "";
                    }
                },
                updateInput(e) {
                    this.inputText = e.target.value;;
                }
            },
        })
    </script>
</body>

편리한 기능이지만 input에서 한글,중국어,일어 를 사용한다면 주의해야한다.
v-model에 마지막 글자가 잘 입력되지 않는다. input데이터가 즉시 바인딩이 되지 않고 조합이 끝난 뒤, 바인딩 된다.
한글은 글자가 조합을 통해 완성되는 특성 때문에 계산과정을 거치는데 IME라는 소프트웨어가 담당한다.

아래와 같이 작성하면 즉시 데이터가 적용되는 걸 확인할 수 있다.

<input type="number" ref="answer" :value="inputText" @input="updateInput">

끝말잇기

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>끝말잇기</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="root">
        <div> {{word}} </div>
        <form v-on:submit="onSubmitForm">
            <input type="text" :value="value" ref="answer" @input="onChangeInput">
            <button> 입력 </button>
            <div>{{result}}</div>
        </form>
    </div>
</body>
<script>
    const app = new Vue({
        el: "#root",
        data: {
            word: "준혁",
            result: "",
            value: ""
        },
        methods: {
            onSubmitForm(e) {
                e.preventDefault();
                if (this.word[this.word.length-1] === this.value[0]) {
                    this.result = "딩동댕"
                    this.word = this.value;
                    this.value = "";
                    this.$refs.answer.focus();
                } else{
                    this.result = "땡"
                    this.value = "";
                    this.$refs.answer.focus();
                }
            },
            onChangeInput(e) {
                this.value = e.target.value;
            }
        }
    });
</script>
</html>


profile
웹 프론트엔드, RN앱 개발자입니다.

0개의 댓글