# 自定义组件

如果内置的组件无法满足开发需求，可以自行开发自定义组件

## Class Component开发方式

下面是一个简单的`Class Component`自定义组件示例

```javascript
import React from 'react';
import { XForm, XComponent, registerComponent } from '@wowpic/xform-react';
import { Input } from 'antd';

// 需要继承XComponent
class Component extends XComponent {
    constructor(props) {
        super(props);

        this.state = {
            value: this.props.value,
            valid: true
        };
    }

    // 触发验证，如果不需要rules校验，想要在组件内自行实现错误提示的，可以通过这个方法取到校验的时机
    // trigger类型有change、submit、blur
    // 可以返回一个值来来更新字段的valid
    validate(trigger, value) {
        if (trigger === 'submit' && !Number.isInteger(value)) {
            return {
                valid: false,
                message: '必须为数字',
                status: 'error'
            };
        }
    }

    // 触发重置，用于获取重置时机，更新组件值
    reset() {
        this.setState({
            value: ''
        });
    }

    onInput(e) {
        const value = e.target.value;
        this.setState({
            value
        });
        // 需要手动触发onChange事件，并且把值传递过去
        this.props.onChange(value);
    }

    // 需要手动触发onBlur事件，主要用于校验时候的blur场景
    onBlur() {
        this.props.onBlur();
    }

    render() {
        const { value } = this.state;

        return (
            <Input value={value} onInput={e => this.onInput(e)} onBlur={e => this.onBlur()}/>
        );
    }
}
// 最后可以注册组件，当然也可以直接传递给type
registerComponent('Component', Component);
```

## Function Component开发方式

下面是一个简单的`Function Component`自定义组件示例

```typescript
import { Input } from 'antd';
import React, { useCallback, useEffect, useState } from 'react';
import { registerComponent } from '@wowpic/xform-react';

const Component = ({
    field,
    value: defaultValue,
    onChange,
    onBlur
}) => {
    const [value, setValue] = useState('');

    const onInput = useCallback(
        (e) => {
            const { value } = e.target;
            // 需要手动触发onChange事件，并且把值传递过去
           onChange(value);
        },
        [onChange]
    );

    // 需要手动触发onBlur事件，主要用于校验时候的blur场景
    const onBlur2 = useCallback(() => {
        onBlur();
    }, [onBlur]);

    // 触发验证，如果不需要 rules 校验，想要在组件内自行实现错误提示的，可以通过这个事件取到校验的时机
    // trigger 类型有 change、submit、blur
    // 最后需要设置下 valid、message、status
    const onValidate = useCallback(async (trigger, value) => {
        let valid = true;
        let message = '';
        if (trigger === 'submit' && !Number.isInteger(Number(value))) {
            valid = false;
            message = '请输入数字';
        }
        const status = valid ? 'normal' : 'error';
        return { valid, message, status };
    }, []);

    // 触发重置，用于获取重置时机，更新组件值
    const onReset = useCallback(() => {
        setValue('');
    }, []);

    // 按照需求自由订阅事件
    useEffect(() => {
        field.onValidate(onValidate);
        field.on('RESET', onReset);

        return () => {
            field.removeListener('RESET', onReset);
        };
    }, []);

    useEffect(() => {
        setValue(defaultValue);
    }, [defaultValue]);

    return <Input value={value} onInput={onInput} onBlur={onBlur2} />;
};

// 最后可以注册组件，当然也可以直接传递给type
registerComponent('Component', Component);
```

## 使用方式

可以通过`registerComponent`去注册组件：

```javascript
registerComponent('Component', Component);
```

也可以直接将自定义组件传递给`type`：

```javascript
{
    key: 'component',
    type: Component
}
```
