TIL 22-06-02

thisisyjin·2022년 6월 2일
0

TIL 📝

목록 보기
57/113

Vue.js

Today I Learned ... Vue.js

🙋‍♂️ Reference Book


DAY 04 - 220602
-8. 컴포넌트 심화
-9. Composition API
-10. Proxy 사용

컴포넌트 심화

부모 컴포넌트에서 이벤트 직접 발생

  • 부모 컴포넌트에서 자식 컴포넌트의 버튼을 클릭하는 이벤트 발생시키기.

ChildCompo.vue

<template>
    <button @click="childFunc" ref="btn">Click</button>
</template>
<script>
export default {
    methods: {
        childFunc() {
            console.log('부모가 발생시킨 이벤트');
        }
    }
}

</script>

ParentCompo.vue

<template>
  <child-compo ref="child_compo" @send-message="sendMessage" />
</template>
<script>
import ChildCompo from './ChildCompo.vue';
export default {
  components: [ChildCompo],
  mounted() {
    this.$refs.child_compo.$refs.btn.click();
  },
};
</script>

부모 컴포넌트의 ref를 child_compo로 설정하여 $refs로 접근할 수 있게 한다.
부모 컴포넌트에서 자식 컴포넌트를 ref로 접근하고, 자식 컴포넌트에서 ref로 사용하는 버튼에 접근할 수 있다.


부모 컴포넌트에서 함수 호출

부모 컴포넌트에서 자식 컴포넌트에 정의된 함수를 직접 호출 가능.

ChildCompo.vue

...
methods: {
    callFromParent() {
      console.log('부모가 호출한 함수');
    }
  }

ParentCompo.vue

<template>
  <child-compo ref="child_compo" @send-message="sendMessage" />
</template>
<script>
import ChildCompo from './ChildCompo.vue';
export default {
  components: {ChildCompo},
  mounted() {
    this.$refs.child_compo.callFromParent();
  },
};
</script>
  • 자식 컴포넌트에 ref로 접근하여 자식 컴포넌트 내에 정의된 모든 함수 호출 가능.

부모 컴포넌트에서 데이터 값 변경

data 필드의 옵션 값을 변경할 수 있음.

ChildCompo.vue

<template>
  <h1>{{ msg }}</h1>
</template>
<script>
export default {
  data() {
    return {
      msg: '',
    };
  },
};
</script>

ParentCompo.vue

<template>
  <child-compo ref="child_compo" />
  <button @click="changeChildData">Change Child Data</button>
</template>
<script>
import ChildCompo from './ChildCompo.vue';
export default {
  components: { ChildCompo },
  methods: {
    changeChildData() {
      this.$refs.child_compo.msg = '제목 바꿔버리기';
    },
  },
};
</script>

ref로 접근하여 $refs에서 데이터를 바꾸 수 있다.


자식->부모로 이벤트/데이터 전달

= 커스텀 이벤트

  • 자식에서 부모로 이벤트를 전달하기 위해서는 $emit을 사용한다.

ChildCompo.vue

export default {
  data() {
    return {
      msg: '자식이 부모에게 보내는 메시지',
    };
  },
mounted() {
    this.$emit('send-message', this.msg);
    // emit의 첫번째 인자는 부모 컴포넌트의 이벤트명 , 두번째 인자는 함수의 파라미터로 전달할 값.
    // 자식이 Mount 되면 부모 컴포넌트의 send-message 이벤트를 호출하는 것.
  },
};

ParentCompo.vue

<template>
  <child-compo @send-message="sendMessage" />
</template>
<script>
import ChildCompo from './ChildCompo.vue';
export default {
  components: { ChildCompo },
  methods: {
    sendMessage(data) {
      console.log(data);
    },
  },
};
</script>
  • 부모에서 커스텀 이벤트인@send-message를 정의함.
    -> 커스텀 이벤트는 자식 컴포넌트에서 $emit으로 호출하게 됨.

  • 부모 컴포넌트에 정의 된 sendMessage 함수가 실행되고,
    자식 컴포넌트로부터 전달받은 데이터(msg)를 파라미터로 받아와서
    부모 컴포넌트에서 사용 가능.


부모 컴포넌트에서 데이터 값 동기화

  • 부모 컴포넌트에서 computed를 사용하면 자식 컴포넌트의 데이터 값이 변할때
    항상 동기화 시킬 수 있다.

ChildCompo.vue

<template>
  <button @click="childFunc" ref="btn">자식 데이터 변경하기</button>
</template>
<script>
export default {
  data() {
    return {
      msg: '기존 메시지',
    };
  },
  methods: {
    childFunc() {
      this.msg = '변경된 메시지';
    },
  },
};
</script>

ParentCompo.vue

<template>
  <button @click="checkChild">자식 데이터 조회</button>
  <child-compo ref="child_compo" />
</template>
<script>
import ChildCompo from './ChildCompo.vue';
export default {
  components: { ChildCompo },
  computed: {
    msg() {
      return this.$refs.child_compo.msg;
    },
  },
  methods: {
    checkChild() {
      alert(this.msg);
    },
  },
};
</script>

  • computed = 기존 데이터 기반으로 새로운 데이터를 활용하기 위해 사용 데이터 값 하나만을 감시하기 위해 사용
  • watch = 데이터 변경이 있어도 처음에 실행됨 실제 데이터 변경이 일어나기 전까지는 실행되지 않음.

Slot

  • 컴포넌트 내에서 다른 컴포넌트를 사용할 때 쓰는 마크업을 재정의, 확장.

  • 컴포넌트의 재활용성을 높여주는 기능.

    <div class="container">
     <header></header>
     <main></main>
     <footer></footer>
    </div>
    

    -> 기본적인 모달의 마크업 구성.

  • 모달의 기본 틀에 해당하는 컴포넌트를 Slot을 이용하여 만들고,
    컨텐츠에 해당하는 부분만 작성하면 통일성이 있음.
    (동일한 사용자경험 UX를 주기 위함)

modalLayout.vue

<div>
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

-> Slot에 name을 지정하여 사용하는 방법. (Named Slots)

slot을 사용하는 컴포넌트에서는 v-slot: 슬롯명 디렉티브를 사용하여 해당 slot 으로
html 코드를 삽입할 수 있음.

(name이 없는 경우 v-slot:default)

SlotUseModalLayout.vue

<modal-layout>
<template v-slot: header>
<h1>팝업 타이틀</h1>
</template>

<template v-slot: default>
<p>팝업 컨텐츠 1</p>
<p>팝업 컨텐츠 2</p>
</template>

<template v-slot: footer>
<button>닫기</button>
</template>
</modal-layout>

v-slot 대신에 단축어로 #로 적어줘도 된다.

<template #header> ... </template>

Provide / Inject

  • 부모 -> 자식 데이터 전달시 Props를 이용하고,
  • 자식 -> 부모 전달(+동기화)시 ref (+computed)를 이용하면 된다.
  • 만약, 계층 구조가 복잡한 경우 멀리 떨어진 컴포넌트로 데이터를 전달할 때
    props를 이용한다면? 굉장히 비효율적이고 복잡한 코드가 된다.

-> 이때, ProvideInject를 사용할 수 있음.
부모 컴포넌트에는 provide 옵션을,
자식 컴포넌트에는 inject 옵션을 통해 데이터 쉽게 전달 가능!

React에서 Provider / Consumer 구조였던 Context API와 유사한 기능임.

ProvideInject.vue

<template>
  <ProvideInjectChild />
</template>

<script>
import ProvideInjectChild from './ProvideInjectChild';
export default {
  components: { ProvideInjectChild },
  data() {
    return {
      items: ['A', 'B'],
    };
  },
  provide() {
    return {
      itemLength: this.items.length,
    };
  },
};
</script>

ProvideInjectChild.vue

<template>
  <div></div>
</template>

<script>
export default {
  inject: ['itemLength'],
  mounted() {
    console.log(this.itemLength);
  },
};
</script>
  • provide 함수를 통해 items의 length를 반환. (=itemLength)

  1. 자식 컴포넌트로 전달하고자 하는 데이터를 provide 에 정의함.
provide() {
    return {
      itemLength: this.items.length,
    };
  1. 부모 컴포넌트로부터 전달받고자 하는 데이터를 inject 에 배열로 정의함.
inject: ['itemLength']

inject를 통해 데이터를 전달받는 자식 컴포넌트에서는
전달받은 데이터가 어떤 부모로부터 전달되는지 확인할 수 X.


참고 - camelCase와 kebab-case

HTML 어트리뷰트는 대소문자 구분이 없기 때문에 브라우저는 대문자를 소문자로 변경하여 읽음.
(예 - userName을 username 으로)

그렇기 때문에 카멜 케이스(대소문자 혼용)로 prop의 이름을 정한 경우에,
DOM 템플릿 안 (template 태그 내) 에서는 케밥 케이스를 사용하여야 올바르게 동작합니다.

Vue.component('blog-post', {
  // camelCasef로 작성해줌
  props: ['postTitle'],
  template: '<h3>{{ postTitle }}</h3>'
})
<blog-post post-title="hello!"></blog-post>
profile
기억은 한계가 있지만, 기록은 한계가 없다.

0개의 댓글