Render 함수를 이용한 컴포넌트 작성

template을 사용하지 않고 render함수를 이용하여 컴포넌트를 작성 할수 있습니다. 이때 createElement 함수를 사용하여 작성합니다.

기본 구성

컴포넌트 작성시의 차이점은 template 속성을 사용 하는 대신에 render 함수를 사용한다는 차이점 뿐입니다. render함수는 return으로 VNode를 반환해주기만 하면 됩니다. VNode 생성은 createElement함수를 호출하면 반환해 줍니다(this.$createElement로도 동일하게 사용 가능).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export default {
name: '',
proprs: {},
created() {

},
data() {
return {}
},

// h를 쓰기도 하고 createElement라고 쓰기도 한다.
render(h) {
return h('div', ['값']);
}
}
createElement 함수 호출
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
createElement(
// {String | Object | Function}
// HTML 태그 이름(사용자가 만든 컴포넌트 태그 이름 포함), 컴포넌트 옵션 또는 함수 중
// 하나를 반환하는 함수. 필수사항
'div',

// {Object}
// 컴포넌트에서 사용할 속성 값을 설정합니다.
// 해당 값은 선택사항 입니다.
{

},

// {String | Array}
// VNode 자식들
// 하위 태그를 작성할때 사용 합니다.
// createElement()를 사용하거나, 문자열을 입력 가능합니다.
// 해당 값은 선택사항 입니다.
[
'문자열',
createElement('h1', '옵션 사용 없이 바로 문자열')
]
)
1
2
3
4
5
6
7
8
9
createElement(
'div',
{
props
},
[
'문자열'
]
)

지금까지 확인결과 VNode 자식값을 사용할시에 배열로 넘기자.

데이터 객체

createElement의 두번째 파라미터로 사용 하는 데이터 객체는 컴포넌트에 속성을 정의 할때 사용하게 됩니다.

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
29
30
31
32
33
{
// v-bind:class와 동일
'class': {
foo: true,
bar: false
},

// v-bind:style와 동일
style: {
color: 'red'
},

// 일반 HTML 속성을 정의할때 사용
attrs: {
id: 'foo'
},

// DOM 속성을 정의할때 사용
domProps: {
innerHTML: 'baz'
},

// v-on:click 등과 같은 역할을 합니다.
on: {
click: this.handlerClcik
},

// 다른 컴포넌트의 slot으로 들어가는 컴포넌트인 경우 슬롯의 이름을 여기에 적어줍니다.
slot: 'slot-name',

// ref를 지정하고 싶으면 해당 key를 사용합니다.
ref: 'refValue'
}

Comment and share

Vue 컴포넌트 작성

Vue에서는 템플릿을 통해서 HTML을 작성하는 것을 권장하고 있습니다. 하지만 특정 상황에서는 자바스크립트를 이용해야 하는 상황이 있습니다. 그렇기 때문에 템플릿 뿐 아니라 자바스크립트로도 컴포넌트를 작성하는 방법에 대해서 알고 있어야 합니다.

싱글 파일 컴포넌트

template, script, style 3개의 태그를 이용하여 하나의 파일에서 작성 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div>
{{ str }}
</div>
</template>

<script>
export default {
name: 'VueSingleFileComponent',
props: {
str: {
type: String
}
}
}
</script>

<style scoped>

</style>
사용하기

다른 컴포넌트에서 import를 통해 사용할수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<vue-string-file-component/>
</template>

<script>
import VueSingleFileComponent from './VueSingleFileComponent.vue';

export default {
name: 'VueView',
components: {
VueSingleFileComponent
}
}
</script>

<style>
</style>

Vue.component를 통해서 등록하면 실제 사용하는 곳에서 import를 할 필요 없이 사용할수 있습니다.

main.js
1
2
3
4
import Vue from 'vue';
import VueSingleFileComponent from './VueSingleFileComponent.vue';

Vue.component('vue-single-file-component', VueSingleFileComponent);
VueView.vue

컴포넌트를 import 하거나 components 속성을 등록 할 필요 없이 사용가능합니다.

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<vue-string-file-component/>
</template>

<script>
export default {
name: 'VueView',
}
</script>

<style>
</style>

String으로 컴포넌트 작성

템플릿을 js의 String으로 정의하는 방법입니다. 위 처럼 vue 확장자를 가진 파일을 따로 생성하지 않고 Vue.component에 직접 등록 합니다.

1
2
3
4
5
6
7
8
9
10
import Vue from 'vue';

Vue.component('vue-string', {
template: '<div> {{ str }}</div>',
props: {
str: {
type: String
}
}
})

Vue.component를 사용하기 때문에 import로 호출만 하고 compoents 속성에 따로 등록 하진 않아도 됩니다.

1
2
3
4
5
6
7
8
<template>
<vue-string/>
</template>
import '../components/vue-render/VueString.js';

export default {
name: 'VueView',
}

Render function을 사용하여 컴포넌트 작성

template을 사용하지 않고 render 함수를 이용해서 컴포넌트를 작성 할수 있습니다. 해당 컴포넌트를 import해서 사용방법은 SPA랑 동일 합니다.

1
2
3
4
5
6
7
8
9
10
11
export default {
name: "VueRenderFunc",
props: {
str : {
type: String
}
},
render(h) {
return h('div', [this.str]);
}
}

결론

기본적으로 SPA 방식으로 작성하는 게 좋다고 생각합니다. js를 활용해야 하는 경우에는 render 함수를 이용하여 작성하는 것도 하나의 선택이 될수 있을거라 생각합니다.

Comment and share

데이터 바인딩

기술적 관점

프로퍼티 값을 타겟 객체에 설정하는 기능입니다.

사용자 관점

사용자 입력값을 어플리케이션 도메인 모델이 동적으로 변환해 넣어주는 기능입니다. 클라이언트 입력값은 대부분 문자열인데, 그 값을 객체가 가지고 있는 int, long, boolean, date 등 심지어 Event, Book 과 같은 도메인 타입으로 변환해서 넣어주는 기능입니다. MVC할때 클라이언트에서 받은 데이터를 객체에 넣어주는 기능이 해당 기능입니다.


PropertyEditor

스프링 3.0 이전까지 DataBinder가 변환 작업시에 사용하던 인터페이스입니다.

단점

PropertyEditor는 값을 set 하는 경우 상태를 저장

PropertyEditor가 값을 set하는 경우 쓰레드마다 값을 공유할수 있어 쓰레드-세이프하지 않습니다. 그렇기 때문에 PropertyEditor의 구현체는 여러 쓰레드에서 공유해서 사용하서는 안됩니다.

Bean으로 등록해서 사용하면 안됩니다.


사용 방법

xml에서 빈 등록시 문자열로 넘어온 값을 타입에 맞게 데이터 바인딩 하기


DataBindingBean

데이터 바인딩에서 사용할 샘플 Bean 클래스

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
public class DataBindingBean {
private String str;
private Date date;
private boolean aBoolean;

public void setStr(String str) {
this.str = str;
}

public void setDate(Date date) {
this.date = date;
}

public void setaBoolean(boolean aBoolean) {
this.aBoolean = aBoolean;
}

@Override
public String toString() {
return "DataBindingBean{" +
"str='" + str + '\'' +
", date=" + date +
", aBoolean=" + aBoolean +
'}';
}
}

spring-bean.xml

DataBindingBean를 Bean으로 등록하기 위한 IoC 컨테이너

1
2
3
4
5
6
7
8
9
10
11
<bean id="dataBindingBean" class="kr.co.spring.DataBindingBean">
<property name="str">
<value>안녕하세요</value>
</property>
<property name="date">
<value>2020-01-09</value>
</property>
<property name="aBoolean">
<value>true</value>
</property>
</bean>
TestClass
1
2
3
4
5
6
7
8
9
public class TestClass {

@Test
public void test() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/spring-bean.xml");
DataBindingBean dataBindingBean = (DataBindingBean) ctx.getBean("dataBindingBean");
System.out.println(dataBindingBean.toString());
}
}

위의 코드를 작성 한 후에 실행 해보면 아래와 같이 타입이 맞지 않다고 에러를 발생시킵니다. xml에서 모든 값을 문자열로 넘겨주었으니 타입이 맞지 않다는 에러가 나오는 것이 당연합니다. 이제 문자열로 값이 넘어오더라도 타입게 맞게 데이터 바인딩이 되도록 수정해 보도록 하겠습니다.

1
...Failed to convert property value of type [java.lang.String] to required type [java.util.Date] for property 'date'...

CustomEditorConfigurer 등록하기


4.0 이전 버전

DataBinding에서 사용이 되는 CustomEditorConfigurer의 변화로 인해서 4.0 이전 버전과 이후 버전의 설정이 변경 되었습니다.

spring-bean.xml

4.0 이전 버전에서는 customEditors의 type이 Map<String, ?> 이었습니다. 아래와 같이 PropertyEditor를 구현한 클래스들을 Bean으로 등록해 주면 됩니다.

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
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date">
<bean class="org.springframework.beans.propertyeditors.CustomDateEditor">
<constructor-arg>
<bean class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd"/>
</bean>
</constructor-arg>
<constructor-arg value="true"/>
</bean>
</entry>

<entry key="java.lang.String">
<bean class="org.springframework.beans.propertyeditors.StringTrimmerEditor">
<constructor-arg value="true"/>
</bean>
</entry>

<entry key="java.lang.Boolean">
<bean class="org.springframework.beans.propertyeditors.CustomBooleanEditor">
<constructor-arg value="true"/>
</bean>
</entry>
</map>
</property>
</bean>

4.0 이후 버전(4.0 포함)

4.0 이후 버전에서는 customEditors의 type이 Map<Class<?>, Class<? extends PropertyEditor>>로 바뀌었습니다. 이제는 Bean이 아니라 클래스 경로를 넘겨 주면 됩니다.

spring-bean.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<!-- 1. entry 태그의 key와 value 속성을 이용하여 작성 -->
<entry key="java.util.Date" value="org.springframework.beans.propertyeditors.CustomDateEditor"/>

<!-- 2. value 태그를 이용하여 작성 -->

<!-- 2가지 모두 사용 가능 -->
<entry key="java.lang.String">
<value>org.springframework.beans.propertyeditors.StringTrimmerEditor</value>
</entry>

<entry key="java.lang.Boolean">
<value>org.springframework.beans.propertyeditors.CustomBooleanEditor</value>
</entry>
</map>
</property>
</bean>

변화가 되면서 PropertyEditor 구현체가 default 생성자가 없으면 아래처럼 에러가 발생합니다.

1
No default constructor found; nested exception is java.lang.NoSuchMethodException: org.springframework.beans.propertyeditors.CustomDateEditor.<init>()

위의 방법은 모든 데이터바인딩에 적용이 되는 것임. DataBindingBean를 위해서 작성 된게 아니라 문자열로 넘어온 값을 Date 또는 Boolean으로 데이터바인딩해야 할 모든 상황에서 사용되게 됨. 데이터바인딩에서 사용될 사용자 PropertyEditor 구현체를 등록 하는 절차임.


PropertyEditorRegistrar

PropertyEditorRegistrar를 구현함으로써 PropertyEditor 등록을 커스텀하게 작성할수 있습니다. 이를 이용하면 default 생성자가 없는 경우에도 등록 할수 있습니다.

CustomEditorRegistrar
1
2
3
4
5
6
7
public class CustomEditorRegistrar implements PropertyEditorRegistrar {
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
registry.registerCustomEditor(String.class, new StringTrimmerEditor(true));
registry.registerCustomEditor(Boolean.class, new CustomBooleanEditor(true));
}
}
1
2
3
4
5
6
7
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<bean class="kr.co.spring.CustomEditorRegistrar"/>
</list>
</property>
</bean>

정상적으로 잘 출력이 되는 것을 확인할 수 있습니다.

1
DataBindingBean{str='안녕하세요', date=Thu Jan 09 00:00:00 KST 2020, bool=true}

Comment and share

Moon Star

author.bio


author.job