Vue.js fallThrough, provide, inject

강정우·2023년 3월 31일
0

vue.js

목록 보기
16/72
post-thumbnail
post-custom-banner

fall through property

BaseButton.vue

    <template>  
      <button>
        <slot></slot>
      </button>
    </template>
     
    <script>export default {}</script>
  • 위와같이 BaseButton이라는 예제 UI component가 있다고 해보자.
    이때 별다른 속성값이 지정이 안 되어있다.

App.vue

    <base-button type="submit" @click="doSomething">Click me</base-button>
  • 그런데 사용할 때 여러 속성값을 지정해줘도 에러가 안 나고 잘 작동한다.

Vue에는 "fallThrough" property(event) 지원이 내장되어 있기 때문이다.

  • 즉, 커스텀 컴포넌트 태그에 추가된 property 및 event는 자동으로 해당 컴포넌트의 템플릿에 있는 root 컴포넌트로 넘어간다.

  • 그럼 App.vue 에서 사용된 속성값들이 BaseButton의 <button>속으로 자동으로 들어간다는 것이다.

  • 내장된 $attrs property(예: this.$attrs)에서 이러한 fallThrough property 에 액세스할 수 있다.

  • 이것은 모든 프로퍼티와 이벤트를 개별적으로 정의하고 싶지 않은 "유틸리티" 컴포넌트 또는 순수한 프리젠테이션 컴포넌트를 구축하는 데 편리할 수 있다.

  • 공식문서

Provide, Inject

  • 위와같은 상황이 아닌, 다른 상황을 봐보자 아래와같은 파일구조이 있다고 가정하자.

  • 아래 사진은 위 사진을 보기 편하게 DOM Tree화 하였다.

  • 만약 위와같이 있을 때 App.vue => Knowledge-element.vue 까지 props을 넘길 때 무수히 많은 불필요한 코드를 넣어야한다. 이를 react에서는 props drilling이라고 하였다. 이를 이를 방지하고자 context API, redux등을 이용하여 props(state)를 관리하였다.

  • 그리고 vue는 이러한 props drilling을 막고자 provide, inject라는 특수 속성이 존재한다.

  • 한 곳에 데이터를 제공하고 삽입, 즉 해당 데이터를 다른 곳에서 사용하는 데 사용할 수 있는 패턴이다.
    하지만 단점으로는 역시 provide와 inject사이에 어떠한 데이터가 움직이는 코드가 없다보니 처음 본 사람은 이것을 일일이 찾아봐야한다는 단점이 있다.

1. 데이터 제공

  • 이때 Config 객체의 아무 곳에나 provide 옵션을 추가하면 된다.

App.vue

<script>
	privide(){
    	return{
        	속성이름 : this.속성이름
            속성이름 : this.메서드이름
        }
    },
</script>
  • 이때 메서드로 참조를 해야 메모리를 2번 잡아먹지 않고 데이터를 갱신했을 때 반영이 되기도 한다.
  • 공급자의 value로는 메서드도 들어갈 수 있다.

2. 데이터 사용

  • inject는 기본적으로 프로퍼티와 동일하게 작동한다. 배열을 제공하고 컴포넌트에서 사용할 제공된 데이터를 전부 참조한다.
  1. string으로 받아야한다.
  2. DOM Tree 구조상 해당 컴포넌트보다 상위컴포넌트에서 provide한 것만 사용할 수 있다.
    즉, DOM Tree상 형제 컴포넌트끼리는 사용이 불가능하다.

사용할컴포넌트.vue

<script>
export default {
  inject:[
  	'provide에서 작성한 속성값'
  ],
  methods:{
  	어떠한메서드(){
    	this.메서드이름()
    }
  }
};
</script>

custom event

  • 지금까지는 데이터(props)를 넘겼는데 그러다면 커스텀 이벤트도 drilling하지 않고 provide inject할 수 있을까?
    • 조금은 다르게 할 수 있다.
  • 버튼을 눌렸을 때 호출되는 함수를 프로퍼티로 넣거나 삽입되는 값을 넣을 수 있다.

App.vue

<knowledge-base :topics="topics" @select-topic="activateTopic"></knowledge-base>

<knowledge-base></knowledge-base>

사용컴포넌트.vue

<template>
  <li>
    <h3>{{ topicName }}</h3>
    <p>{{ description }}</p>
    <button @click="$emit('select-topic', id)">Learn More</button>
  </li>
</template>

<script>
export default {
  props: ['id', 'topicName', 'description'],
  emits: ['select-topic'],
};
</script>


<template>
  <li>
    <h3>{{ topicName }}</h3>
    <p>{{ description }}</p>
    <button @click="selectTopic">Learn More</button>
  </li>
</template>

<script>
export default {
  inject:['selectTopic'],
  props: ['id', 'topicName', 'description'],
  emits: ['select-topic'],
};
</script>
  • 여기서 inject해온 selectTopic은 함수이다. 클릭이 발생하면 실행되는 함수인 것이다.
    여기에서 함수를 가리키고 provide와 inject 메커니즘을 사용해서 함수를 값으로 가져온다.

provide(App.vue)

...
<script>
  provide(){
    return{
      topics:this.topics,
      selectTopic : this.activateTopic
    }
  },
  methods: {
    activateTopic(topicId) {
      this.activeTopic = this.topics.find((topic) => topic.id === topicId);
    },
  },
</script>
  • 이때 실행()하는 것이 아닌 pointing만 해 주는 것, 안내만 해주는 것이다.

filter vs splice

  • provide/inject 기능의 원리 때문에 그렇다.

  • provide 메서드에 객체가 포함되어 있는데 이에 Vue가 provide 메서드를 실행하여 해당 컴포넌트를 생성한다.

  • 이후 inject를 통해 provide의 속성의 배열을 리소스가 필요한 모든 컴포넌트에 삽입한다.
    이는 배열이므로 그 값이 메모리에 저장되는데 JavaScript의 참조 값이다.

  • 리소스를 추가할 때와 같이 push나 unshift를 통해서 배열을 변경한다고 하면 기존에 입력했던 메모리 내 동일한 배열에도 변경 사항이 반영된다. 이에 따라 Vue가 해당 변경 사항을 인식할 수 있는 것이다. 그리고 이 resources 키가 삽입된 모든 위치도 이 변경 사항을 인식하게 된다.

  • 반면 filter를 사용하면 배열시 새로 생기고 이 새로운 배열은 다른 모든 컴포넌트에는 입력되지 않는다.

  • 그럼 어떻게 하면 좋을까?
    인수로 식별자를 받은 다음 해당하는 index를 찾아 바꿔주는 방식을 선택하면 된다.

메서드(식발자){
	const resIndex = this.속성값.findIndex(res => res.id === 식별자);
    this.속성값.splice(resIndex, 1)
}
profile
智(지)! 德(덕)! 體(체)!
post-custom-banner

0개의 댓글