hc-components
Version:
基于react的通用组件库
164 lines (148 loc) • 4.31 kB
JSX
import React from 'react';
import PropTypes from 'prop-types';
export class DataSet extends React.PureComponent {
static formatter = {};
static themeOptions = {};
static theme = (themeOptions) => {
DataSet.themeOptions = themeOptions;
}
static propTypes = {
Component: PropTypes.any,
childProps: PropTypes.object,
onChange: PropTypes.object,
value: PropTypes.any,
data: PropTypes.object,
getResolver: PropTypes.func,
defaultValue: PropTypes.string,
format: PropTypes.string,
formatter: PropTypes.func,
children: PropTypes.any,
spin: PropTypes.bool,
}
static defaultProps = {
data: {},
childProps: {}
}
constructor(props, context) {
super(props, context);
this.state = {
pending: props.spin
};
this.stateUpdater = {};
if (props.getResolver) {
this._resolver = props.getResolver(props.defaultValue);
}
/**
* prop = {
* value: Object | Function,
* format: String,
* formatter: Function,
* setter: String | Function
* }
*/
Object
.keys(props.data)
.forEach(name => {
const prop = props.data[name];
if (prop.value) {
const originValue = typeof prop.value === 'function' ? prop.value.call(this, this.props) : prop.value;
const formatter = this.getFormatter(props.formatter, name);
// formatter是一系列解决组件schema的格式化函数
if (formatter) {
this.state[name] = formatter.call(this, prop.schema, originValue);
} else {
this.state[name] = originValue;
}
}
if (prop.setter) {
const setter = props.childProps[prop.setter];
this.stateUpdater[prop.setter] = (updateFn) => (this.setState((prevState) => {
let newValue = typeof updateFn === 'function' ?
updateFn.call(this, prevState[name]) :
updateFn;
const formatter = this.getFormatter(props.formatter, name);
if (formatter) {
newValue = formatter.call(this, prop.schema, newValue);
}
setter && setter(newValue);
return {[name]: newValue};
}));
}
});
}
componentDidMount() {
this._resolver && this._resolver.then(iState => {
iState.pending = false;
this.setState(iState, this.props.onChange);
});
}
handleResolve = (value, params) => {
if (this.props.spin) {
this.setState({
pending: true
});
}
if (this.props.getResolver) {
const resolver = this.props.getResolver(value, params);
resolver.then(iState => {
iState.pending = false;
this.setState(iState, this.props.onChange);
});
}
}
getFormatter(formatter, name) {
if (!formatter && DataSet.formatter) {
const comFormatter = DataSet.formatter[this.props.format] || {};
formatter = comFormatter[name];
}
return formatter;
}
getRealInstance() {
return this._instance;
}
render() {
let option = {};
const {children, Component, childProps} = this.props;
let type;
if (Component) {
type = Component.name;
if (type && DataSet.themeOptions[type]) {
option = DataSet.themeOptions[type];
}
if (children) {
return (
<Component
ref={instance => this._instance = instance}
{...option}
{...childProps}
{...this.state}
{...this.stateUpdater}>{children}</Component>
);
} else {
return (<Component
ref={instance => this._instance = instance}
{...option}
{...childProps}
{...this.state}
{...this.stateUpdater} />);
}
} else {
type = children.type.name;
if (type && DataSet.themeOptions[type]) {
option = DataSet.themeOptions[type];
}
return React.cloneElement(React.Children.only(children), {
ref: instance => {
this._instance = instance;
if (typeof children.ref === 'function') {
children.ref(instance);
}
},
...option,
...childProps,
...this.state,
...this.stateUpdater
});
}
}
}