Vue.js(4)

쌩 초보의 개발로그·2023년 1월 16일
0

vue.js

목록 보기
4/7
post-thumbnail

뷰의 스코프(범위)

뷰의 경우 컴포넌트로 화면을 구성하므로 같은 웹 페이지라도 데이터를 공유할 수 없다.
그 이유는 컴포넌트마다 자체적으로 고유한 유효 범위를 갖기 때문인데 뷰는 각 컴포넌트의 유효 범위가 독립적이기 때문에 다른 컴포넌트의 값을 직접적으로 참조할 수 없다.

ex)

<div id="app">
  <my-component1></my-component1>
  <my-component2></my-component2>
</div>

 <script>
      //첫번째 컴포넌트
      const cmp1 = {
        template : '<div>첫 번째 지역 컴포넌트 : {{ cmp1Data }}</div>',
        data : function(){
          return {
            cmp1Data : 100
          }
        }
      };

      //2번째 컴포넌트
      const cmp2 = {
        template : '<div>두 번째 지역 컴포넌트 : {{ cmp2Data }}</div>',
        data : function(){
          return {
            cmp2Data : cmp1.data.cmp1Data
          }
        }
      };

      new Vue({
        el : '#app',
        components : {
          'my-component1' : cmp1,
          'my-component2' : cmp2
        }
      });
    </script>

첫번째 지역 컴포넌트 : 100
두번째 지역 컴포넌트 :

출력을 해보면 첫번째 컴포넌트 값을 참조하였던 두번째 값은 빈 값이다.
이유는 컴포넌트의 scope 때문에 2가 1을 직접 참조가 불가능 하기 때문이다.

부모 자식간의 컴포넌트 관계(데이터 주고 받기)

컴포넌트 관계도에서 상-하 관계에 있는 컴포넌트 통신은

  • 위에서 아래로는 데이터(props)를 내리고
  • 아래에서 위로는 이벤트를 올린다 (event emit)

props 속성

  • 상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달할 때 사용하는 속성
  • 뷰에서 상위 컴포넌트와 하위 컴포넌트의 개념??
    -> 이는 컴포넌트를 등록함과 동시에 뷰 인스턴스 자체가 상위 컴포넌트가 되기 때문
    즉, 기존에 있는 인스턴스에 새로운 컴포넌트를 등록하면 기존에 컴포넌트는 상위 컴포넌트가 되고, 새로 등록된 컴포넌트는 하위 컴포넌트가 된다.(이렇게 새 컴포넌트를 등록한 인스턴스를 최상위 컴포넌트 즉, root component 라고 한다.)
  • 주의할점 : props 변수 명을 카멜 기법(aBow)으로 정의하면 html 태그에서 사용할 때는 케밥 기법(-)으로 선언해야 한다.
<child-component v-bind:props 속성 이름="상위 컴포넌트의 data 속성"></child-component>

Vue.component('child-component', {
	props: ['props 속성 이름']
});
  • 예시
<div id="app">
	// 4
	<child-component v-bind:propsdata="message"></child-component>
</div>

<script>
	// 2
	Vue.component('child-component', {
    	// 3
    	props : ['propsdata'],
        // 5
        template : '<p> {{ propsdata }}</p>'
    });
    
    // 1
    new Vue({
    	el : '#app',
        data : {
        	message : 'Hello Vue!'
        }
    });
</script>
  1. new Vue()로 인스턴스 하나 생성
  2. Vue.component()를 이용하여 child-component 등록
  3. child-component의 내용에 props 속성으로 propsdata를 정의
  4. 태그의 v-bind 속성을 보면 v-bind:propsdata="message" 상위 컴포넌트의 message 속성 값 'Hello Vue!' 텍스트를 하위 컴포넌트인 propsdata로 전달
  5. {{ propsdata }} 는 위에서 넘겨받은 값은 'Hello Vue!'로 치환
    결론 : 뷰 인스턴스의 data 속성에 정의된 message 속성값을 하위 컴포넌트에 props로 전달

같은 레벨의 컴포넌트 간 통신

동일한 상위 컴포넌트를 가진 하위 컴포넌트들 간의 통신은 아래와 같이 해야 한다.

  • Child(하위) -> Parent(상위) -> Children(하위 2개)
  • 참고 : 컴포넌트 간의 직접적인 통신은 불가능하도록 되어 있는게 Vue의 구조이다

이벤트 발생과 수신

  • props는 상위에서 하위 컴포넌트로 데이터를 전달하는 방식이었다면, $emit()은 이벤트를 발생시켜 상위 컴포넌트에 신호를 보내는 속성
  • $emit() : 이벤트 발생 속성
  • v-on: : 이벤트 수신 속성
// 이벤트 발생
this.$emit('이벤트명');

// 이벤트 수신
<child-component v-on:이벤트명="상위 컴포넌트의 메서드명"></child-component>

이벤트 발생시킬 때의 this는 하위 컴포넌트를 가르킨다.


<div id="app">
	// 3
	<child-component v-on:show-log="printText"></child-component>
</div>

<script>
	Vue.component('child-component', {
    	// 1
    	template : '<button v-on:click="showLog">show</button>',
        // 2
        methods: {
        	showLog : function(){
            	this.$emit('show-log');
            }
        }
    });
    
    const app = new Vue({
    	el : '#app',
        data : {
        	message : 'Hello, Vue'
        },
        methods : {
        	// 4
        	printText : function(){
            	console.log("received an event");
            }
        }
    });
</script>
  1. [show] 버튼을 클릭하면 클릭이벤트 v-on:click="showLog"에 따라 showLog() 실행

  2. showLog() 메서드 안에 this.$emit('show-log') 실행되면서 show-log 이벤트 발생

  3. show-log 이벤트는 에 정의한 v-on:show-log에 전달되고, v-on:show-log의 대상 메서드인 최상위 컴포넌트의 메서드 printText() 실행

  4. printText() 메서드 안에 console.log 내용인 'received an event' 출력

    결론 : .$emit()으로 이벤트를 발생시키고, v-on으로 이벤트를 받는다.

이벤트 버스 (EventBus)

  • 위에서는 상.하위 컴포넌트 간의 데이터 주고받기 위한 내용이었다면, 이벤트버스(EventBus)는 관계없는 컴포넌트 간의 통신을 말한다.
  • $emit() : 이벤트 발생 속성
  • $on() : 이벤트 수신 속성
// 이벤트 버스를 위한 추가 인스턴스 1개 생성
var eventBus = new Vue();

// 이벤트를 보내는 컴포넌트
methods: {
	메서드명 : function(){
    	eventBus.$emit('이벤트명', 데이터);
    }
}

// 이벤트를 받는 컴포넌트
methods: {
	created : function(){
    	eventBus.$on('이벤트명', function( 데이터 ){
        
        });
    }
}

<div id="app">
	<child-component></child-component>
</div>

<script>
	// 1
	var eventBus = new Vue();
    
    Vue.component('child-component', {
    	// 2
    	template : '<div>하위 컴포넌트 영역입니다. <button v-on:click="showLog">show</button></div>',
        // 3
        methods : {
        	showLog : function(){
        		eventBus.$emit('triggerEventBus', 100);
            }
        }
    });
    
    var app = new Vue ({
    	el : '#app',
        created : function(){
        	// 4
        	eventBus.$on('triggerEventBus', function(value){
            	console.log("이벤트를 전달받음. 전달받은 값 : ", value);
            });
        }
    });
</script>
  1. 먼저 이벤트 버스로 활용할 새 인스턴스를 1개 생성하고 eventBus라는 변수에 참조한다. 이제 eventBus 변수로 새 인스턴스의 속성과 메서드에 접근 가능
  2. template 속성에는 '하위 컴포넌트 영역입니다.' 라는 텍스트와 [show] 버튼을 추가
  3. methods 속성에는 showLog() 메서드 정의하고, 메서드 안에는 eventBus.$emit() 을 선언, triggerEventBus 라는 이벤트를 발생하는 로직을 추가하고, 이벤트가 발생할 때 수신하는 쪽에 100이라는 값을 함께 전달한다.
  4. 상위 컴포넌트의 created 라이프 사이클 훅에 eventBus.$on() 으로 이벤트를 받는 로직을 선언, 발생한 이벤트 triggerEventBus를 수신할 때 value로 앞에서 전달되는 이자 값 100을 받아 콘솔에 출력

(4) 느낀점

뷰의 컴포넌트는 자체적으로 고유한 독립을 가지기 때문에 다른 컴포넌트를 참조할 수 없다는게 좀 충격이었다.
그래서 그 서로간에 참조를 할 수 있는 방법을 공부해보았는데, 공부를 하며 아직 이해되지 않는 부분이 꽤 있었다.
위에서 아래로, 아래에서 위로 서로 통신하는데 각기 다른 방법을 사용을 하는것도 Vue.js를 공부하며 이런 방식을 쓰는구나 라고 생각을 하며 자바만을 공부했던 나에게 아직 컴퓨터 언어의 세상은 넒고 나의 지식은 매우 좁구나라고 느꼈다.

profile
안녕하세요 쌩 초보 장휘주 입니다. 열심히 하는 개발자가 될게요.

0개의 댓글