일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 프로그래머스 코딩테스트
- html
- 코테스터디
- 알고리즘문제
- 프로그래머스 코테
- 프로그래머스알고리즘
- 프로그래머스코테
- 코테준비
- next.js 에러
- 코딩테스트
- js
- next.js
- 자바스크립트
- mysql
- 개발자
- 프로그래밍
- 프로그래머스 레벨0
- 프로그래머스 알고리즘
- 정보처리기사
- 알고리즘공부
- CSS
- 알고리즘스터디
- 정처기기출
- 프로그래머스코딩테스트
- 1일1코테
- 프로그래머스
- 코딩
- 코테공부
- Redux-Toolkit
- 프로그래머스 Lv.0
- Today
- Total
계발하는 개발자
[Vue.js] 컴포넌트 provide(제공) / inject(주입) 이해하기 본문
어제 포스팅했던 mixins 옵션을 알기 전에, 부모 컴포넌트에서 자식 컴포넌트로 메서드 전달을 위해 기존 사용하였던
provide/inject 에 대해 정리해볼까 한다.
먼저 이와 비슷한 기능을 하는 props가 아닌 provide/inject를 고려했던 이유는 자식컴포넌트의 경우 부모컴포넌트에서 사용하는 단순 메서드가 필요한 것이지, 부모측 데이터는 필요없어서였다.
이런 경우 props로 전달받기엔 많은 번거로움이 있다고 생각했다.
이 포스팅은 일전 사용하였던 경험을 바탕으로 정리한 것이며, 지금은 해당 코드 블럭을 mixins으로 대체해서 코드상에서는 제외되었다.
Provide/inject 란?
- 목적
- 상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달하거나, 부모-자식 계층 구조를 따르지 않는 컴포넌트 간에 데이터를 공유하는 데 사용된다.
- 주로 복잡한 컴포넌트 구조에서 다양한 컴포넌트 간에 데이터를 공유하거나 전역 상태 관리와 유사한 기능을 구현할 때 사용된다.
- 세부 옵션 정의
- provide : 부모 컴포넌트가 데이터 제공을 위해 사용하는 옵션
- inject - 자식 컴포넌트가 데이터 사용을 위해 사용하는 옵션
- 특징
- provide 하는 데이터는 반응성을 가지지 않는다.
- 이 말인 즉슨, provide한 데이터가 변경되어도 inject한 데이터는 변경되지 않는다.
- 이를 반응형으로 지원하기 위해선 ref/reactive나 computed를 이용해야 한다.
- 부모에서 자식으로 데이터 전달을 할 때 유용하지만 컴포넌트간 의존성 증가, 데이터 복잡성 증가라는 단점을 가진다.
- vue 공식문서에서는 아래와 같이 일반 어플리케이션 코드에서는 사용하지 않는 것이 좋다 한다.
- provide 하는 데이터는 반응성을 가지지 않는다.
`provide`와 `inject`는 주로 고급 플러그인/컴포넌트 라이브러리를 위해 제공됩니다. 일반 애플리케이션 코드에서는 사용하지 않는 것이 좋습니다.
[부모컴포넌트 : goods-comp]
// [2] 뷰컴포넌트 서브페이지 상품
Vue.component("goods-comp", {
template: `
<section>
<div class="container">
<div class="pagewrap" v-on="initSetSubSrc()">
<!-- 상품리스트 박스 -->
<div class="prdbx">
<div class="prdwrap">
<!-- 상품리스트 -->
<ul class="ui-col4">
<template v-for="(v,i) in prdData[dataNum()]">
<template v-for="(a,b) in prdData[dataNum()][i]" v-if="b === $store.state.curUrl2 || $store.state.curUrl2 === '전체'">
<li v-for="(x,y) in a" :key="y" v-on:mouseover="handleMouseOver" v-on:mouseleave="handleMouseLeave" v-on:click="getData(prdData[dataNum()][i], y)">
<div class="ui-prod-bx">
<a href="#">
<div class="prod-detail-img">
<img v-bind:src="'./images/goods/' + $store.state.curUrl0 + '/' + i + '/' + x.img + '.jpg'" alt="상품이미지">
</div>
</a>
<div title="찜하기" class="product_like" v-on:click="addWish(prdData[dataNum()][i],y,1)">
<button type="button" class="fa-solid fa-heart"></button>
</div>
</div>
<div class="item-detail">
<div class="prod-txt">
<strong class="brand">슈펜</strong>
<p>{{x.name}}</p>
</div>
<span class="original-price">
<em>{{numberWithCommas(x.oprice)}}</em>
<span v-if="x.oprice">원</span>
</span>
<br>
<span class="discount-price">
<em>{{numberWithCommas(x.dprice)}}</em>
<span>원</span>
</span>
<span class="percent-price" v-if="x.oprice && x.dprice">
<em>{{calculateDiscount(x.oprice,x.dprice)}}</em>
</span>
<div class="box_grade">
<div class="star">
<span v-if="x.review">{{'(' + x.review + ')'}}</span>
</div>
</div>
</div>
</li>
</template>
</template>
</ul>
</div>
</div>
</div>
</div>
<!-- 여기부터 디테일페이지! -->
<dt-comp></dt-comp>
</section>
`,
위 코드는 기존 삭제 전 코드이고, 내용이 많기 때문에 일정 부분은 잘라내었다.
문제가 되었던 부분은 부모인 goods-comp의 [numberWithCommas, calculateDiscount, minusBtn, plusBtn] 이라는 이름의 메서드들을 자식인 dt-comp에서도 호출되도록 하는 것이었다.
아무리 부모 컴포넌트 안에 한데 묶여있더라도 부모 컴포넌트의 메서드를 자식 컴포넌트에 전달해주지 않고서는 호출이 불가했다.
methods: {
// 정규식함수(숫자 세자리마다 콤마해주는 기능)
numberWithCommas: function (x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
},
// 정가/할인가 비교해서 할인율 계산
calculateDiscount: function (oprice, dprice) {
// 정가와 할인가 중 하나라도 빈값이면 빈값 반환
if (!oprice || !dprice) {
return "";
}
const discount = ((oprice - dprice) / oprice) * 100;
return Math.floor(discount) + "%";
},
// 더하기함수
plusBtn: function () {
let num = $(".opt_num input").val();
num++;
// 업데이트
$(".opt_num input").val(num);
store.state.result = num;
},
// 빼기함수
minusBtn: function () {
let num = $(".opt_num input").val();
num--;
if (num === 0) return;
// 업데이트
$(".opt_num input").val(num);
store.state.result = num;
},
}
그래서 방법을 알아보던 중 알게된 것이 바로 provide/inject 였다.
(사실 이와 관련한 방법으로 그 유명한 props도 있는데 이건 또 차차 정리해보려한다.)
본격적인 provide/inject 사용을 위해 부모컴포넌트 provide 옵션에 정의된 함수를 자식컴포넌트로 내보낸다.
<!-- 여기부터 디테일페이지! -->
<dt-comp></dt-comp>
</section>
`,
provide: function () {
return {
// dt-comp에 전달할 메서드들
numberWithCommas: this.numberWithCommas,
calculateDiscount: this.calculateDiscount,
plusBtn: this.plusBtn,
minusBtn: this.minusBtn,
};
},
내보냈으니 이제 받아줘야겠지?
해당 메서드를 필요로하는 자식컴포넌트 등록한 구역으로 가서 inject 한다.
말그대로 provide - inject 주거니 받거니 하는 관계가 export - import 랑도 비슷해보인다.
[자식컴포넌트 : dt-comp]
// [5] 뷰컴포넌트 - 상품디테일
Vue.component("dt-comp", {
inject: ["numberWithCommas", "calculateDiscount", "plusBtn", "minusBtn"],
template: dtData.dtComp,
mounted() {
// 부모 컴포넌트에게서 전달받은 메서드 호출!
if (typeof this.numberWithCommas && this.calculateDiscount && this.plusBtn && this.minusBtn === "function") {
this.numberWithCommas();
this.calculateDiscount();
this.plusBtn();
this.minusBtn();
}
그리고 자식 컴포넌트가 DOM에 마운트될때 해당 함수를 실행하도록 한다.
그런 후에 렌더링될 dt-comp 템플릿으로 가서 특정한 액션이 있는 경우나 인자값을 넘겨줘야 하는 경우에 인자값을 전달해서 호출해준다.
<div class="price">
<div class="txt-def">
<em>
{{numberWithCommas($store.state.dtoprice)}}
<span v-if="$store.state.dtoprice">원</span>
</em>
</div>
<div class="txt-dsc">
<em>{{numberWithCommas($store.state.dtdprice)}}</em>
<span>원</span>
<span class="txt-percent">
<em>{{calculateDiscount($store.state.dtoprice, $store.state.dtdprice)}}</em>
</span>
</div>
</div>
<div class="opt_num">
<a href="#" role="button" class="minus" v-on:click.prevent="minusBtn()">수량감소</a>
<a href="#" role="button" class="plus" v-on:click.prevent="plusBtn()">수량증가</a>
<label>
<input type="number" class="num" title="수량" value="1">
</label>
</div>
그러면 아래같이 에러없이 각 메서드 기능들이 잘 작동한다!
(구동이 잘 되는 부분에 형광펜 처리하였다.)
위의 방법으로 부모컴포넌트로부터 메서드들을 전달받아 자식 컴포넌트에서도 동일한 함수를 실행시켰다.
가격에 세자리 콤마, 원가와 할인가를 비교하여 구한 할인률 표시, 수량조절 및 수량에 따른 총 합계가 계산되어 표시된다.
* 이해에 도움이 됐던 자료 및 출처 :
Provide(제공) / Inject(주입) | Vue.js
ko.vuejs.org
[VueJS] provide, inject 사용하는 방법 알아보기
VueJS에서 컴포넌트 사이의 데이터를 전달하는 방법중 하나인 Provide / Inject 방법에 대하여 알아봅니다.
webisfree.com
'💻 Frontend > Vue.js' 카테고리의 다른 글
[Vue Cli] images 저장 경로 설정 | public과 assets 중 어디에? (0) | 2023.08.24 |
---|---|
[Vue.js 시작하기] Vue Cli 설치 (0) | 2023.08.23 |
[Vue.js] 컴포넌트간 공통기능 메서드를 묶는 Mixins(믹스인) (0) | 2023.08.16 |
[Vue.js] 쇼핑몰PJ/매장찾기 | 지역명 클릭시 지역 중분류 데이터 출력1 (0) | 2023.08.16 |
[Vue.js] 강제 클릭이벤트 발생 (+ DOM조작 수행시 주의사항) (0) | 2023.05.13 |
dev_genie
@dev_genie
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!