4 뷰 라이프사이클
source: categories/study/vue-principle/vue-principle_4.md
4.1 vue-devtools와 기타 정보들
- 크롬 확장프로그램에서 설치 (vue.js devtools)
- vue 성능 체크 (몇 프레임인지)
- 그리고 몇번 렌더링되는지
- 이 모든 것들을 체크해볼 수 있다. (체크해보자.)
0. 컴포넌트 이름짓는 방법?
- 컴포넌트 이름은 무조건 두 단어 이상으로 짓는게 필수
- 한 단어로 지으면 기존에 이미 존재하는 태그들과 겹칠 수 있음
table
이라는 컴포넌트가 있다면 이table
컴포넌트가 HTML의table
을 가리키는지vue-component
의table
을 가리키는지 애매함- 그래서
vue component
는 웬만하면 2단어 이상으로 작성 vue
에서 필수라고 적어놓음, 공식문서에.
1. 지난번 webpack dev server 사용할 때, dist/app.js 결과물이 없는데 잘만 실행됨. 왜?
- network 패널보면 dist/app.js를 제대로 가지고오고 있음. 없는데. 어떻게?
- webpack dev server는 웹팩의 아웃풋을 파일로 내보내서 저장하는 것이 아니라 메모리에 저장.
- 그래서 파일이 실제로 존재하는게 아님. 가상 메모리에 존재.
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const path = require('path');
// webpack 처리를 할 때 아래 객체를 사용한다.
// entry, module, plugins, output 4가지가 주된 설정, 나머지는 부가적인 설정
module.exports = {
mode: 'development', // 개발중일 땐 development, 배포할 땐 production
devtool: 'eval', // 개발할 땐 eval, 배포할 땐 hidden-source-map
// eval로 하면 웹팩 빌드 속도가 빨라진다.
// 이 모드별로 app.js에 나오는 내용이 달라진다.
resolve: { // 확장자 처리 가능
extensions: ['.js', '.vue'], // 해당 확장자들은 import 할 때 생략 가능
},
entry: {
// app <- 하나로 합쳐질 파일의 이름 app.js
app: path.join(__dirname, 'main.js'),
},
module: { // webpack의 핵심
rules: [ // javascript 파일을 합칠 때 어떤 방식으로 합칠건지를 명시
{
test: /\.vue$/,
use: 'vue-loader', // use: 'vue-loader'라고 작성해도된다.
},
{
test: '/\.css$/',
use: [
'vue-style-loader',
'css-loader',
],
}
],
},
plugins: [ // module 처리 이후 output 으로 내보내기 전에 한번 더 가공해주는 역할
new VueLoaderPlugin(),
],
output: {
filename: '[name].js', // 위에 정의한 app 이라는 이름이 왼쪽 [name]에 매칭되어 들어온다.
path: path.join(__dirname, 'dist'), // output 경로
publicPath: '/dist',
},
}
위의 publicPath
에 /dist
라고 적어줘야지 메모리상에도 dist/app.js
위치에 생긴다.
2. :class와 :style
- 데이터 중심으로 사고해라
:class
,:style
은 객체 형식을 지원한다.- 자바스크립트에서
-
는 마이너스를 뜻하기 때문에-
이 들어간 CSS 속성은 대문자로 작성한다. background-image
는backgroundImage
3. sprite image
http2
가 나온 요즘에는 스프라이트 이미지를 안 써도 되긴함- 옛날에는 여러 이미지 동시 요청보내는게 매우 무거운 작업이었음
- 그래서 이렇게 이미지를 하나로 합치는 것을 많이 했었음
4. computed
- 데이터 옆에 뭔가 부수적인 것들이 달려서 화면에 적용될 때
- 해당 식들을 그대로
template
태그 안에 쓰지말고computed
활용 (caching
)
5. vue 라이프사이클
- beforeCreate
- Created
- beforeMount
- mounted
- beforeUpdate
- updated
- beforeDestroy
- destroyed
- 컴포넌트의
data
,computed
,method
등을 다 읽고 template과 연결 // 여기까지가created
- 다 해놨는데 화면에만 안 붙인게
created
이다. - 즉, 자바스크립트 상에서만 존재하는게
created
- 다 해놨는데 화면에만 안 붙인게
- 마지막에 화면에다 붙여주고난 이후에
mounted
가 된다.- 화면에까지 존재하는게
mounted
- 화면에까지 존재하는게
6. vue devtools 분석
- 항상
vue devtools
를 보며 개발해야된다. data
와computed
가 실시간으로 바뀌는 것이 보인다.frame
이 60 이하로 내려가면 시각적으로 버벅임이 느껴진다. 최대한 60 이상으로 되도록 성능 최적화에 신경을 써야된다.component render
에서 각 라이프사이클 함수들이 몇번 호출되는지 나온다.
7. async는 왜 쓰나요?
await
쓰려고 사용한다.- 콜백 지옥 등을 벗어나 코드 작성을 깔끔하게 할 수 있다.
async function test () {
await new Promise(); // 이렇게 프로미스 인스턴스 앞에 await를 쓸 수 있다.
}
4.1.1 가위바위보 (뷰 라이프사이클)
RockScissorsPaper.vue
<template>
<div>
<!-- `url(https://en.pimg.jp/023/182/267/1/23182267.jpg) ${imgCoord} 0` 이렇게 데이터에 추가적인 문자열이 붙어있으면 캐싱을 못한다. -->
<!-- 이런 경우에 computed를 사용. caching을 자동으로 해주는 것이 성능에 좋다. -->
<!-- <div id="computer" :style="{ backgroundImage: `url(https://en.pimg.jp/023/182/267/1/23182267.jpg) ${imgCoord} 0` }"></div> -->
<div id="computer" :style="computedStyleObject"></div>
<div>
<button type="button" @click="onClickButton('바위')">바위</button>
<button type="button" @click="onClickButton('가위')">가위</button>
<button type="button" @click="onClickButton('보')">보</button>
</div>
<div>{{ result }}</div>
<div>현재 {{ score }}점</div>
</div>
</template>
<script>
// 아래 imgCoord data에 바로 0, -142px, -284px 값을 주면 다른 작업자가 응? 이게 뭘 뜻하는거지? 하면서 헷갈려 할 수 있다.
// 이렇게 명시적으로 적어주는 것이 좋다.
const rspCoords = {
rock: '0',
scissor: '-142px',
paper: '-284px',
}
const scores = {
scissor: 1,
rock: 0,
paper: -1,
}
const computerChoice = (imgCoord) => {
return Object.entries(rspCoords).find(function (v) {
return v[1] === imgCoord;
})[0]
}
let interval = null;
export default {
name: 'RockScissorsPaper',
data() {
return {
imgCoord: rspCoords.rock,
result: '',
score: 0,
}
},
computed: {
computedStyleObject() {
return { backgroundImage: `url(https://en.pimg.jp/023/182/267/1/23182267.jpg) ${this.imgCoord} 0` }
},
},
beforeCreate() {
},
created() {
// 만들어지긴 했지만 화면에 보이기 전
},
beforeMount() {
},
mounted() {
// 화면에 보이고 난 후
this.changeHand();
},
beforeUpdate() {
},
updated() {
},
beforeDestroy() {
// mounted 에서 실행한. 지금처럼 setInterval 같은..
// 해당 컴포넌트가 사라진 이후에도 이때 실행된 setInterval은 계속 실행된다.
// 가위바위보 컴포넌트가 사라졌는데도 해당 setInterval이 계속 실행되면 문제가 생긴다. - 쓸데없는 작업을 계속하는 거니깐 성능상의 문제.
// 이런게 메모리 Leak, 메모리 누수이다.
clearInterval(interval); // 해당 코드는 destroyed 에서 해도되지만, 보통 beforeDestroy 에서 많이한다.
},
destroyed() {
},
methods: {
changeHand() {
interval = setInterval(() => {
if (this.imgCoord === rspCoords.rock) {
this.imgCoord = rspCoords.scissor;
} else if (this.imgCoord === rspCoords.scissor) {
this.imgCoord = rspCoords.paper;
} else if (this.imgCoord === rspCoords.paper) {
this.imgCoord = rspCoords.rock;
}
}, 100)
},
onClickButton(choice) {
clearInterval(interval);
const myScore = scores[choice];
const cpuScore = scores[computerChoice(this.imgCoord)];
const diff = myScore - cpuScore;
if (diff === 0) {
this.result = '비겼습니다.';
} else if ([-1, 2].includes(diff)) {
this.result = '이겼습니다.';
this.sore += 1;
} else {
this.result = '졌습니다.';
this.score -= 1;
}
setTimeout(() => {
this.changeHand();
}, 1000)
},
}
}
</script>
<style scoped>
#computer {
width: 142px;
height: 200px;
background-position: 0 0;
}
</style>