Vue 강의 내용 정리
[router 설계 필요 ]
news
ask
jobs
세개의 페이지가 필요하고
이를 url에 맞게 뿌려주면 됨.
특정 상세 페이지가 따로 있음
사용자 정보 페이지 (user view)
[vue cli 2 vs vue cli 3]
-
명령어
- 2.x : vue init ‘프로젝트 템플릿 이름’ ‘파일 위치’
- 3.x : vue create ‘프로젝트 이름’
-
웹팩 설정 파일
- 2.x : 노출 Y WEBPACK.config이 밖으로 나와 있음 WEBPACK 에다 곧바로 수정하면 되었음
- 3.x : 노출 N WEBPACK.config이 숨겨있음 webpack 조작할 때 별도의 필요한 부분 추가해줘야함
-
프로젝트 구성
- 2.x : 깃헙의 템플릿 다운로드
- 3.x : 플러그인 기반으로 기능 추가
-
ES6 이해
- 2.x : 필요 없음
- 3.x : 필요
[ES lint 해제하는 방법]
/*eslint-disable*/ 을 올려두면 해당 코드는 적용 x
[vue의 프로젝트 순서]
- vue create 로 생성하여 vue cli 3 를 실행하면 프로젝트 생성
- 프로젝트 생성 main.js 가 해당 application의 구조도가 됨
- router 를 등록하는 방법
1) vue-router 를 설치 (npm install vue-router --save)
2) router 폴더 (src아래에 생성) > index.js 생성
3) index.js에 url 정보와 components정보를 입력
4) routes 를 export 시켜주고 main.js에서 import해줌
5) App.vue에서 <router-view>를 추가해주면 router에서 컴포넌트를 해당
태그에 뿌려주는 것을 확인할 수 있음
[태그 새롭게 등록]
<!--ToolBar 일 때는 tool-bar 로 바꿔서 사용가능-->
<!--Pascal 케이스는 자동완성 x-->
<!--케밥 케이스는 자동완성 o 그리고 간략 확인가능-->
[router-link to=’url’]
앵커가 박히게 됨.
[api]
api 를 불러오면 해당 정보들을 배열형태로 받을 수 있음
[this]
vue에서 this를 찍으면 기본적으로 컴포넌트 자체가 찍히게 되는듯하다. 그러나 axios에서 then 을 처리한 후 this를 찍으면 axios가 찍히게 된다.
this 는 기본은 전역 그러나 생성자 함수에서는 그 생성자 함수 비동기 호출 시 this (then 에 나오는 this) 는 undefined이다. (이럴 경우 this binding 해줘야 함) 그러나 arrow func 일 때 this는 최종 생성자 this 를 가리킴 -> 그래서 arrow function 방식을 많이 사용한다. this 바인딩 할 필요가 없으므로
[created]
components 가 생성될 때 생성되는 곳이 created() 이다. ES6 에서
created : fucntion() {
}
를 created()로 사용할 수 있음
lifecycle hook이라고 부르고 이런 것들이 beforeMount, mounted 등등이 있다.
이와 연관된 내용이
- Reactivity in Depth 라고 하는 내용이 있음.
나중에 한번 볼 것
[비동기처리, callback, promise]
-
callback 종료되는 시점에 실행되는 함수 (함수로 인자를 넘길 수 있으므로 가능함)
1) fetchData() 실행 2) 그 안의 result 배열 생성 3) ajax 실행 > 데이터 받아옴. 4) console.log 에 그 결과가 찍힘이런 순으로 코딩이 되어있는데 1>4 순이 아니라
1,2,4,3 순으로 실행 됨 먼저 console.log 를 먼저 처리하고 그 다음에 ajax의 처리가 완료됨
이게 비동기처리의 기본 임
그러면 console.log를 ajax안에서 실행하면 올바른 순서로 찍힘
callback hell 에 빠질 수 있음
-
Promise 와 resolve 콜백 관계에서 Promise가 끝나고 resolve를 통해 data 값을 넘겨주게 되는 것임.
Vuex 간단한 구조도
before NewsView 에서 API를 적용해서 호출
after NewsView <- Vuex <- API
중간에 Vuex 를 사용하여 호출할 예정임. 컴포넌트의 관리의 의미가 있음
Vuex는 상태관리도구 컴포넌트 간에 데이터 넘겨줄 때 사용
-
Vuex 를 만들어서 인스턴스를 추가해주면 개발자 도구에서 Vue 탭의 두번째 셀렉션으로 Vuex 를 사용할 수 있게 된다.
-
Vuex에서의 action상태는 dispatch로 가져올 수 있다.
-
Vuex에서의 상태에 대하여. Action : 모든 비동기 호출 값을 가져온다. Mutation : 이를 State에 담기 전 상태임. 여기를 거쳐감. State : 최종 바뀔 값.
순서는 다음과 같다. Action(API로 부터 값을 받음)
- mutation (값을 state로 넘겨줌) : 이 과정이 왜 있는지는 강사도 모르고 있음
-
state (여기 안의 변수를 내보낼 수 있음)
- 이 때, 상태에 따라 데이터 넘겨줄 때 써야하는 용어들이 정해져있음 여기 를 참고하고 action -> mutation 은 commit vue component에서 action에 접근하여 데이터 가져올때는 dispatch를 사용해야함
위의 전체 상태 값에 대한 코드를 store 에 담아서 export 시켜주면
main.js에서 store를 import 시켜줬기 때문에 모든 컴포넌트에서 store를 사용할 수 있게 된다.
그 다음 원하는 컴포넌트에서 this.$store.dispatch(‘actions 안의 함수 이름’) 위와 같이 사용하면 위의 state에 저장한 값에 접근할 수 있게 된다.
Destructuring (구조 분해 문법)
관련링크 위 페이지에 긴 내용이 담겨있음.
var arr = [1, 2, 3, 4];
var obj = {
a: 10,
b: 20,
c: 30,
};
위와 같은 배열, 객체의 선언에서
var { a, b, c } = obj;
위를 실행할 시 a, b, c 에 각각 10,20,30 이 들어가게 된다.
자주 사용하는 방법은 아래와 같다.
var josh = {
language: 'javascript',
position: 'front-end',
area: 'pangyo',
hobby: 'singing',
age: '102',
};
var language = josh.language;
var position = josh.position;
var area = josh.area;
var hobby = josh.hobby;
var age = josh.age;
위와 같이 사용하던 것을
var { language, position, area, hobby, age } = josh;
console.log(language); // javascript
console.log(position); // front-end
console.log(area); // pangyo
console.log(hobby); // singing
console.log(age); // 102
위와 같이 사용할 수 있다는 것이다.
vuex를 사용할 때, context.context 사용시 {commit} 으로 간략하게 사용할 수 있게 된다.
vuejs map 헬퍼에 대하여…
- AskView 부분을 보면 주석으로 this.$store.state.ask 를 어떻게하면 간략하게 사용할 것이냐에 대한 내용을 적어두었음.
그에 대한 설명을 여기에 기록함.
1 함수를 사용함.
단순하다. computed : 아래에 메서드를 하나만들어 거기서 return this.$store.state.ask 을 넣어주면 끝
2 이제부터는 vuex 맵헬퍼 함수를 사용하여 가져올 것이다.
- mapState 사용법 map헬퍼함수를 사용할 때는, … (spread 구문을 사용하는 듯하다) 왜 spread 구문이냐 예를 들어
...mapState([
'count'
])
위와 같이 사용하였다면.. state 내의 모든 존재하는 value들을 검색하여 그 중에 count 를 가져오겠다는 뜻이다.
...mapState({
ask : state => state.ask
})
여기서는 위와 같이 사용하였는데 => 인자 안에 state 를 넣으면 state의 값은 state 의 모든 값을 다 가져온다. (물론 여기서는 created 될 때, FETCH_ASK 를 호출하였기 때문에 다른 값에는 아무 것도 안들어가지만 state.ask 에만 값이 들어가 있게 됨.) 결과적으로 위 코드에서 ask 라는 프로퍼티 안에 state.ask 값을 넣어준 것과 같이 동작한다.
- mapGetter(객체 표기법) index.js 안에
getters:{
fetchedAsk(state){
return state.asks;
}
},
위와 같이 getters 를 만들어 fetchedAsk 를 추가한다. getters 란 기본적으로 데이터에 접근할 때 발생한다.
그 때 fetchedAsk 를 발생시켜 state.ask 를 가져갈 수 있도록 해주는 것이다.
...mapGetters({
ask : 'fetchedAsk'
})
위와 같이 선언하여 index.js 에서 ask 값을 가져온다. 혹은 배열형태로.. …mapGetters([ ‘fetchedAsk’ ]), 위와 같이 사용할 수 있다.
Dynamic Route matching (동적 라우트 매칭)
url 에 ?id=(아이디명) 이거로 다음 페이지로 이동할 수 있다.
라우팅 routes/index.js 에 보면
{
path:'/user/:id',
component: UserView,
},
위와 같이 설정하고
라우팅 링크를 설정할 때
<router-link v-bind:to="`/user/${item.user}`">{{item.user}}</router-link>
위와 같이 설정 다시말해 v-bind:to=/user/ + id 의 구조로 설정하면
해당하는 곳으로 이동했을 때
vue 탭의 개발자도구로 들어가면 data.$route.params 안에 (여기 객체 값 확인 필요) id 값이 넘어가는 것을 알 수 있다.
위에서 어디는 params 에 넘기고 어디는 query에 넘김 방법론적인 거 나중에 이 방법 저 방법 다 배울 것
- 다이나믹 라우팅의 순서
- 라우터 > index.js에 라우터 정보 등록
- 해당 페이지 컴포넌트로 이동했을 때 params Or querys 정보를 다룰 것
-
데이터 fetch 순서 (vuex 쪽이긴한데 오늘 알게 됨)
- vue component 생성
- vuex 를 사용하여 dispatch실행 => store의 actions 로 가게 됨
- 해당 하는 함수 (FETCH_ITEM) 실행
- axios등을 실행하여 데이터 가져옴
- 여기 데이터 mutation으로 옮김
- mutation에서 state에 셋팅한 정보들을 component에서 사용 가능
-
font awsome 페이지 참고
<link href="/your-path-to-fontawesome/css/all.css" rel="stylesheet" />
<!--load all styles -->
- html 에 해당하는 content를 가져왔을 때 태그를 인식시켜서 출력시켜줄 경우
v-html 을 사용하면 끝
라우터 트랜지션
라우터에 의해 페이지가 바뀔 때, 좀더 스무스하게 바뀔 수 있도록 할 수 있음
리팩토링
구조를 바꿀 것임. 공통으로 사용되는 부분을 컴포넌트로 뽑아낼 것임 ex) 하나의 글(피드)를 컴포넌트로 만들 수 있음.
- 일단, style 태그 안에 scoped 속성을 주면 해당 컴포넌트에만 영향을 끼치겠다는 소리임
컴포넌트 만들어서 사용할 때, 명명 규칙의 변화가 됨을 유의할 것. 예를들어, ListItem.vue 로 컴포넌트를 생성해서 가져왔으면 태그는 list-item으로 생성해야함. 대문자로 구분이 - 로 구분이 되고 소문자로 변경됨.
핵심은 분기를 어떻게 해줄 것이냐하는 것임. this.$route; 에 접근할 수 있음. 이 안에 있는 정보, path or name을 통해 분기를 주면 됨
그 외에는 v-if 를 사용하는 방법 설명함. 어떤 애는 있는데 어떤 애는 없으면 이를 판단하여 분기해주면 됨.
사용자 컴포넌트 데이터 흐름
-
첫번째 방법 userView 안에 userProfile 컴포넌트를 가져왔다. 이 경우
- userView에서 fetch dispatch하는 부분에서 데이터 가져옴
- 위 데이터를 아래 컴포넌트인 userProfile 에서 사용할 수 있음
- this.$store.state.user 를 통해 사용하면 됨
-
두번째 방법 userView 안에
태그에 <user-profile :info="userInfo"></user-profile>위와 같이 :info 안에 데이터를 넘겨준다. (물론 userView 안에 computed 속성에 userInfo 값이 있어야한다.) 그러면 userProfile 안에는 props 로 info 값을 받을 수 있다.
-
두가지 방법의 비교 직빵으로 가져오는 것과 info 로 보내주고 받는 것.
1번은 UserView => Vuex => API => Vuex => UserProfile => UserView
2번은 UserView => Vuex => API => Vuex => UserView => UserProfile => UserView
조금더 Vuex의 구조에 적합하게 만들려면 표현하는 부분에 바로 땡기는 것이 간편하게 만든 것이기 때문에
곧바로 가져가는 1번 방법이 낫고
그러나 구조적으로 의미를 주고 싶으면 2번으로 사용하는게 낫다.
slot 의 사용
UserProfile 에서
<slot name="username">
<!-- 상위 컴포넌트에서 정의할 영역 -->
</slot>
위와 같이 slot을 뚫어주면
UserVue 에서
<div slot="username">{{ userInfo.id }}</div>
와 같이 사용하면 된다. 그러면 해당 위치에 내가 원하는 정보를 그대로 넘겨줄 수 있다.
언제 사용하는가 ex) ItemView 에서는 info.id 값을 넘겨주는데 UserView 에서는 info.user 값을 넘겨준다고 하면 분기를 만들수도 있겠지만 위와 같이 처리하는게 직관적으로 보기가 좋은듯
router-link 에 물려서 보내줄 수 있음.
spinner
“웹 페이지의 로딩 상태를 나타내는 컴포넌트를 의미합니다.”
- Spinner.vue 를 생성한다. 걍구글링해서 복붙함.
- javascript
props: {
loading: {
type: Boolean,
required: true,
},
},
props 에 loading 값을 설정할 것, 3. bus 셋팅 “Spinner는 여러 컴포넌트에서 사용할 수 있기 때문에, Event Bus를 이용하는 것이 좋습니다. event bus는 단순히 이벤트를 공유할 수 있도록 하는 bus입니다.” bus.js 생성 (단순 vue 만들어서 export 시켜줌)
- bus를 사용하여 App.vue 의 created()와 beforeDestroy() 안에서 사용함.
created(){
bus.$on('start:spinner', this.startSpinner);
bus.$on('end:spinner', this.endSpinner);
},
beforeDestroy(){ // 이벤트 등록하고 나면 반드시 종료시켜줘야함.
bus.$off('start:spinner', this.startSpinner);
bus.$off('end:spinner', this.endSpinner);
}
- 엘리먼트 created() 에서 페이지 생성 될 때 해당 로딩 화면 보여지도록 수정
bus.$emit('start:spinner'); // start:spinner 발생 (이때 부터 로딩값 보여줌)
setTimeout(() => {
// setTimeout 은 로딩을 인위적으로 보도록 만든 것임
this.$store
.dispatch('FETCH_JOBS') // 데이터받아와서
.then(() => {
bus.$emit('end:spinner'); // 정상적으로 받아오면 spinner 종료
})
.catch(err => {
console.log(err);
});
}, 1000);
하이오더 컴포넌트 (HOC)
“하이오더 컴포넌트는 컴포넌트의 로직(코드)을 재사용하기 위한 고급기술” 위의 spinner를 만든다 하면, 모든 엘리먼트 파일에 해당 동일한 코드를 추가해줘야했다.
이를 공통 컴포넌트로 만들어서(하이오더 컴포넌트) 언제든 재사용하게 만들겠다는 것이다.
-
CreateListView.js 이게 하이오더 컴포넌트라 할 수 있음.
-
router 쪽에서 사용된 component의 갯수가 적어짐. 그냥 CreateListView 만 쓰면 됨.
컴포넌트의 구조가 어떻게 되는가. NewsView > ListView(hoc로 생상된 컴포넌트) > ListItem
Mixin
“공통으로 사용하고 있는 로직, 기능들을 재사용하는 방법”
하이오더 컴포넌트의 단점은 NewsView > ListView(hoc로 생상된 컴포넌트) > ListItem
Level이 깊어짐. 통신에 있어서 불편함이 발생할 수 있음.
Mixin을 사용하면
- 코드가 깔끔해짐.
- spinner의 효율이 좋아짐.
데이터 호출 시점
1. 컴포넌트 라이프 사이클 훅
- created() 인스턴스(컴포넌트)가 생성되자 마자. 호출되는 로직들. data 관찰, computed 속성, methods 접근 가능 화면에 mounted 에 접근은 안됨
‘컴포넌트 생성되자마자’ 타이밍이 핵심!
2. 라우터 네비게이션 가드.
router.beforeEach(fucntion (to, from, next){
// to: 이동할 url
// from : 현재 url
// next : to에서 지정한 url로 이동하기 위해 꼭 호출해야하는 함수
})
이런식으로 라우팅 되기전 시점에 호출할 수 있음.
-
특정 “url로 접근하기 전”에 동작을 정의! 시점은 라우터 네비게이션 가드가 먼저임.
-
라이프 사이클 훅의 문제점. 해당 내용이 update되기 전에 그 전의 내용을 먼저 보여줬다가 그다음 내용이 뜸.
왜 그러냐면 vuex(store) > state 에서 list라는 데이터를 공유하고 거기에 덮어쓰기를 반복하기 때문임. (news, jobs, ask 따로 쓸 때는 괜찮음)
라우터 네비게이션 가드 사용법
component: NewsView,
beforeEnter: (to, from, next) => {
console.log(to);
console.log(from);
console.log(next);
next();
},
beforeEnter 를 사용하면 url 이동하기 전에 동작을 줄 수 있다. 여기서 auth 같은걸로 구분해서 if문 걸어서 못가게 만들 수도 있음.
-
라우터 네비게이션을 사용하게 되면 반드시 그 중간중간에 기다릴 수 있도록 인지시키는 도구가 필요하다.
- spinner
- progress bar
- loading bar 등등이 되어야 함!
async await
함수들의 단축, 가독성 증가 함수 앞에 async 를 붙이면 그 안에 함수 호출할 때, await 를 사용할 수 있음.
async await 의 예외처리는 try - catch 로 사용
handleException(error) 를 만들어서 사용하는 경우도 있다.
외부 라이브러리 모듈화
-
이유 Vue.js 관련 라이브러리가 없을 때 일반 라이브러리를 결함할 수 있어야함. ※ state of js 페이지가 있음
- 종류
- 차트
- 데이트 피크
- 테이블
- 스피너
-
chart.js
- 차트 라이브러리 npm 설치
- 설치된 라이브러리를 import 로 App.vue 에서 로딩
- import 시킬 때 import Chart from “chart.js/auto”; 위와 같이 /auto 를 붙여줘야한다. (안그러면 딴거 참조해오기 때문에 에러남. 버전에 따른 문제라고 함.)
- mounted() 라이프 사이클 훅에서 차트를 그림 여기 사용할 때 script DOM 에 접근해야하므로 mounted 된 후에 사용해야 함.
-
차트를 컴포넌트화 시킴
1) component 등록
2) 해당 컴포넌트에 원하는 대로 setting
3) App.vue 에서 import 시켜서 가져옴reference 속성
document.getelementById('app'); document.querySelector('#app'); $('#app');vue에서 제공하는 위의 기능
<div ref="app" id="app">hello </div>script안에
this.$refs.app; (이렇게 사용하면 됨);reference를 사용하면 좋은점. DOM 으로 변환될 때 사용 안됨. 그러므로 중복 값을 만들어도 사용 가능함! - 컴포넌트의 플러그인화 매번 컴포넌트 가져올 때마다 chart.js 라이브러리를 불러와야함. 라이브러리를 플러그인으로 만들 수 있음. vuejs 플러그인 공식 문서 Vue.use(라이브러리 명) - 뷰에서 제공하는 플러그인을 가져온 경우를 말함
Vue.prototype.$_Chart = Chart;
에 대한 의미.
모든 컴포넌트에서 쓰는 $_Chart 는 여기 chart.js 에서 가져오는 것이다. ($_Chart는 공식문서 권고 표기방법)
- 컴포넌트 통신을 이용한 컴포넌트 기능 결합
v-bind:propsdata="..."이런식으로 해서 넘겨줄 수 있고 이벤트에 대해선
1) 컴포넌트에서
onclick: fucntion() {this.$emit('refresh:chart');}- App.vue 에서
v-on:refresh:chart="refreshChart" - App.vue methods: 안에서 refreshChart 정의
컴포넌트 디자인 패턴
4가지 패턴
- Common - 기본적인 컴포넌트 등록 방식, 컴포넌트 통신
- Slot - 마크업 확장이 가능한 컴포넌트
- Controlled - 결합력 높음
- Renderless - 데이터 처리 컴포넌트
1) Common (지금까지 살펴봤던 방식과 같음)
- 컴포넌트 설정
App- AppHeader
- AppContent
v-bind:변수명 으로 전달
- props 를 통해서 전달할 때는
props{
title: 'String',
}
이런식으로 타입을 지정할 수 있음. (속성=기본적인 속성)
2) slots
slot은 컴포넌트와 다르게 사이에 텍스트가 올 수 있음.
보통 컴포넌트는
[1] props에서 사용할 때는 (차이점을 보기위해..)
data() 안에서 ```items: ['1', '2', '3', '4'];``` 이렇게 하고
<item v-for="item in items" :propsData="item"></item>
// item.vue 로 가서
item props:['propsData'] //로하고
{{propsData}} //를 사용했음.
[2] slot에서 사용할 때는
data 필요 없음
//item.vue 안에서 <slot> 여기는 정의할 때마다 계속 정의 됨 </slot>
약간 치환된다고 보면 됨. slot => 내용으로
만약에 리스트를 찍어주다가
어떤 요청.,. 난 이 경우는 그림을 보여주고 싶어 그러면
굳어진 컴포넌트라면 불가능 함.
쇼핑몰 상품, 모달 같은 것들을 맘대로 확장가능 스타일도 넣을 수 있음. 상당히 동적인처리가 가능해짐.
[3] controlled
자 정리해보면, props 방식의 문제를 알아야 함.
상위 컴포넌트 => props로 전달 => 하위 컴포넌트에서 props 변경 => 에러발생
상위 컴포넌트 => v-model 로 연결 => 하위 컴포넌트에서 value 와 input 이벤트 => 이벤트 발생 시 toggle 메서드 생성
[4] Renderless
- render() function 에 대한 내용
render: fucntion(createElement){
# return createElement('태그이름', '태그 속성', '하위 태그 내용');
return createElement('p', 'Hello Vue');
}
render: h=>h(App) // 에 대한 내용 위의 코드의 원리대로
render: fucntion(createElement){
# return createElement('태그이름', '태그 속성', '하위 태그 내용');
return createElement(App);
}
createElement : h로 (hypertext)
여기 createElement 는 Virtual DOM 을 의미하는데 vue의 창시자 EvanU 에 의해 hypertext의 약자 h로 사용
render: h=> h(App);
//이렇게 되는 것임.
//하위 데이터를 상위로 보낼 수 있음.
render() {
this.$scopedSlots.default ({
response: this.response,
loading: this.loading
})
}
위와 같이 정의하면
상위 컴포넌트에서
<div slot-scoped="{response, loading}">
<!-- 안에서 해당 데이터를 받아올 수 있음. --></div
>
CLI 를 통한 배포
npm run build
dist 폴더 밑에 hosting 할수 있는 파일이 생성됨.
Netlify 을 이용한 배포
bae directory 만 설정해서 배포하면 해당 사이트가 잘 나옴.
그런데, url/(path) 이렇게 url 이 지정될 경우
페이지를 찾을 수 없다고 뜬다.
딱 url로만 들어가야 잘 뜬다.
왜냐면 서버에서 해당 path url을 알 길이 없기 때문이다.
이에 대해서 설정을 해줄 수 있는 파일이
public/_redirects 에서 설정해줄 수 있다.
위 파일에
Netlify settings for single-page application
/* /index.html 200
를 추가해준다.
Netlify설정 위 링크 Netlify 에 배포할 때 설정 값임.
위와 같이 추가하면 그 뒤의 route 정보를 가져가서 확인하는듯하다.
env 파일
어플리케이션에 공통으로 접근할 수 있는 변수를 만들겠다는 것임.
1) 전역 파일 .env 파일을 만든다.
2) APP_TITLE=HELLO 이렇게 만들고
3) App.vue 에서
//created() 안에
console.log(process.env.APP_TITLE); //을 넣어서 실행
//=> undefined 이 뜬다.
4) 원래는 dotenv 라는 패키지 가져와서, 뭐 어쩌구 저쩌구해서 정의해야만 사용할 수 있었음.
5) vue cli 3 이상부터 지원하는 기능이 있음. 앞에 VUE_ 를 붙이면 됨.
6) console.log(process.env.VUE_APP_TITLE); 를 사용하면 끝!