[TIL] Vue(5)

JaeungE·2022년 5월 11일
0

TIL

목록 보기
23/29
post-thumbnail

Props


props 전달

객체의 데이터를 컴포넌트의 props로 전달하려고 할 때, 보통은 아래처럼 작성한다.


user: {
	id: 1,
    name: JaeungE
}
<UserComponent :id="user.id :name="user.name"></UserComponent>

하지만 객체의 모든 데이터를 props로 전달하고자 한다면, 아래와 같이 축약이 가능하다.


<UserComponent v-bind="user"></UserComponent>

prop 이름을 따로 정의하지 않고, 단지 v-bind 디렉티브에 객체를 넘긴다는 것에 유의하자.



단방향 데이터 흐름

Propstop-down의 단방향 데이터 흐름을 가지며, 하위 컴포넌트에서 props를 수정할 수 없다.

따라서 props로 받은 데이터의 수정이 필요하다면, 아래처럼 컴포넌트 내부에서 별도의 data로 만든 뒤에 수정하는 패턴을 사용하거나, 커스텀 이벤트를 사용한다.


props: ['propValue'],
data() {
  return {
    value: this.propValue
  }
}



props 타입 정의

props객체로 정의한 뒤 keyprops, valuetype을 지정할 수 있다.


<script>
export default {
  props: {
    message: String
  }
};
</script>

props 하나의 type이 아닌 여러 type을 가져야 한다면 배열로 선언할 수 있다.


<script>
export default {
  props: {
    message: [String, Number]
  }
};
</script>

또한, 아래처럼 type 부분을 객체로 정의하고 default 프로퍼티를 이용해서 기본값을 지정할 수 있다.


<script>
export default {
  props: {
    message: {
      type: [String, Number],
      default: 'Default Message'
    }
  }
};
</script>

이 외에도 required 프로퍼티로 반드시 전달되어야 하는 props를 지정할 수 있으며, 참조형 데이터의 기본값은 항상 함수 형태로 반환해야 한다.


<script>
export default {
  props: {
    message: {
      type: [String, Number],
      default: 'Default Message',
      required: true
    },
    user: {
      type: Object,
      default: function() {
        return {
          id: 1,
          name: JaeungE
        }
      }
    }
  }
};
</script>

만약 기본적인 type 체크가 아닌, 커스텀한 유효성 검사를 하고 싶다면 validator 프로퍼티에 함수를 정의해서 사용할 수 있다.



Non-Prop 속성

컴포넌트에 정의된 속성들 중 props로 정의되지 않은 속성들은 $attrs라는 내장 객체에 저장되며, 이 속성을 Non-Prop 속성이라고 한다.

Non-Prop 속성은 컴포넌트 내부에서 this.$attrs를 이용해 접근이 가능하며, 루트 노드가 하나인 경우 자동으로 해당 노드에 적용된다.


App

<template>
  <MyComponent
    class="title"
    @click="title += '~~!'" 
  />
</template>

MyComponent

<template>
  <h1
    :class="$attrs.class"
    @click="$attrs.onClick"
  >
  <div>
  	content
  </div>
</template>

만약 루트 노드가 하나일 때, Non-Prop 속성이 하위 컴포넌트로 적용되는 것을 원하지 않는다면 컴포넌트의 inheritAttrs 프로퍼티를 false로 설정하도록 한다.


<script>
export default {
  inheritAttrs: false,
  ...
}
</script>





커스텀 이벤트


유효성 검사

컴포넌트 내부에서 emits 프로퍼티를 이용해 커스텀 이벤트를 명시하는 것 외에도, 객체 리터럴을 이용해서 유효성 검사가 가능하다.


<template>
  <div>
    <button @click="$emit('plus')">
      Count + 1
    </button>
    <button @click="$emit('minus', count)">
      Count - 1
    </button>
  </div>
</template>
<script>
export default {
  props: {
    count: {
      type: Number,
      default: 0
    }
  },
  emits: {
    plus: null,
    minus: (count) => {
      if(count > 0) {
        return true;
      } else {
        console.error('count is not less than 0');
        return false;
      }
    }
  },
};
</script>



양방향 데이터 바인딩

컴포넌트에서 기본적으로 아래와 같이 props를 이용한 양방향 데이터 바인딩을 할 수 있다.

App

<template>
  <h1>
    {{ msg }}
  </h1>
  <Hello 
    :message="msg"
    @update="updateMsg" />
</template>

<script>
import Hello from '~/components/Hello';

export default {
  components: {
    Hello
  },
  data() {
    return {
      msg: 'Hello Vue!!'
    };
  },
  methods: {
    updateMsg(value) {
      this.msg = value;
    }
  }
};
</script>

Hello

<template>
  <label>
    <input 
      :value="message"
      @input="$emit('update', $event.target.value)">
  </label>
</template>

<script>
export default {
  props: {
    message: {
      type: String,
      default: ''
    }
  },
  emits: ['update']
};
</script>



컴포넌트의 propsv-model 디렉티브를 이용하면 간단하게 양방향 바인딩 구현이 가능하며, 별도의 이름을 정의하지 않으면 modelValue라는 propsv-model에 지정한 데이터가 바인딩 된다.

이때 이벤트 이름은 eventName:modelValue 형태로 작성해야 한다는 점을 주의하도록 하자.


App

<template>
  <h1>
    {{ msg }}
  </h1>
  <Hello 
    v-model="msg" />
</template>

<script>
import Hello from '~/components/Hello';

export default {
  components: {
    Hello
  },
  data() {
    return {
      msg: 'Hello Vue!!'
    };
  }
};
</script>

Hello

<template>
  <label>
    <input 
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)">
  </label>
</template>

<script>
export default {
  props: {
    modelValue: {
      type: String,
      default: ''
    }
  },
  emits: ['update:modelValue']
};
</script>



만약 기본으로 사용되는 modelValue의 네이밍을 변경하고 싶다면, 아래와 같이 v-model:propName 형태로 변경할 수 있다.


App

<template>
  <h1>
    {{ msg }}
  </h1>
  <Hello 
    v-model:message="msg" />
</template>

<script>
import Hello from '~/components/Hello';

export default {
  components: {
    Hello
  },
  data() {
    return {
      msg: 'Hello Vue!!'
    };
  }
};
</script>

Hello

<template>
  <label>
    <input 
      :value="message"
      @input="$emit('update:message', $event.target.value)">
  </label>
</template>

<script>
export default {
  props: {
    message: {
      type: String,
      default: ''
    }
  },
  emits: ['update:message']
};
</script>

이 외에도 v-model을 반복적으로 사용해서 여러 개의 데이터를 양방향 데이터로 바인딩할 수 있다.





Slots


컴포넌트 태그의 content<slot> 태그를 이용해서 가져올 수 있으며, content가 없는 경우 <slot> 태그의 content에 기본값을 정의할 수 있고, 이 값을 Fallback이라고 한다.

또한 content의 내용이 다중 요소일 때, v-slot:<name> 디렉티브를 이용해서 <slot>태그의 name 속성을 통해 위치를 매핑할 수 있다.

v-slot#으로 축약이 가능하다.


App

<template>
  <Hello>
    <template #before>
      <h1>is Before Content</h1>
    </template>
    <template #after>
      <h1>is After Content</h1>
    </template>
    <template #end />
  </Hello>
</template>

<script>
import Hello from '~/components/Hello';

export default {
  components: {
    Hello
  }
};
</script>

Hello

<template>
  <slot name="before" />
  <h1>Hello</h1>
  <slot name="after" />
  <slot name="end">
    <h1>is End</h1>
  </slot>
</template>





Refs


컴포넌트에서 특정 요소를 찾고 싶을 때, 해당 요소에 ref 속성을 정의하고 this.$refs 객체를 이용해서 참조할 수 있다.


<template>
  <h1 ref="title">
    Title~!
  </h1>
</template>

<script>
export default {
  mounted() {
    console.log(this.$refs.title);
  }
};
</script>

만약 ref 속성이 HTML요소가 아닌 컴포넌트에 적용되어 있다면, 해당 컴포넌트의 참조를 얻어오게 된다.


App

<template>
  <Hello ref="hello" />
</template>

<script>
import Hello from '~/components/Hello';

export default {
  components: {
    Hello
  },
  mounted() {
    const hello = this.$refs.hello;
    console.log(hello.$refs.title);
  }
};
</script>

Hello

<template>
  <h1 ref="title">
    Title~!
  </h1>
</template>

위의 코드를 실행하면 App 컴포넌트가 마운트 됐을 때, Hello 컴포넌트의 h1 요소를 콘솔에 출력한다.





0개의 댓글