default value 和 value 逻辑优化

This commit is contained in:
2betop 2021-06-16 18:25:09 +08:00
parent 51284b67b7
commit b875d02321
21 changed files with 134 additions and 99 deletions

View File

@ -36,6 +36,8 @@ const defaultOmitList = [
'disabledOn',
'component',
'detectField',
'defaultValue',
'defaultData',
'required',
'requiredOn',
'syncSuperStore'
@ -234,7 +236,7 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
const renderer = this.renderer as RendererConfig;
schema = filterSchema(schema, renderer, rest);
const {data: defaultData, ...restSchema} = schema;
const {data: defaultData, value: deafultValue, ...restSchema} = schema;
const Component = renderer.component;
return (
@ -243,6 +245,7 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
{...restSchema}
{...chainEvents(rest, restSchema)}
defaultData={defaultData}
deafultValue={deafultValue}
$path={$path}
$schema={schema}
ref={this.refFn}

View File

@ -1,7 +1,7 @@
import React from 'react';
import upperFirst from 'lodash/upperFirst';
import {Renderer, RendererProps} from '../factory';
import {autobind} from '../utils/helper';
import {autobind, detectPropValueChanged, getPropValue} from '../utils/helper';
import {Icon} from '../components/icons';
import {resolveVariable} from '../utils/tpl-builtin';
import {filter} from '../utils/tpl';
@ -93,12 +93,9 @@ export class Audio extends React.Component<AudioProps, AudioState> {
state: AudioState = {
src:
this.props.value ||
(this.props.src
? filter(this.props.src, this.props.data, '| raw')
: '') ||
resolveVariable(this.props.name, this.props.data) ||
'',
getPropValue(this.props, props =>
props.src ? filter(props.src, props.data, '| raw') : undefined
) || '',
isReady: false,
muted: false,
playing: false,
@ -131,24 +128,22 @@ export class Audio extends React.Component<AudioProps, AudioState> {
componentWillReceiveProps(nextProps: AudioProps) {
const props = this.props;
if (
props.value !== nextProps.value ||
filter(props.src as string, props.data, '| raw') !==
filter(nextProps.src as string, nextProps.data, '| raw')
) {
this.setState(
{
src:
nextProps.value ||
filter(nextProps.src as string, nextProps.data, '| raw'),
playing: false
},
() => {
this.audio.load();
this.progress();
}
);
}
detectPropValueChanged(
nextProps,
props,
value =>
this.setState(
{
src: value,
playing: false
},
() => {
this.audio.load();
this.progress();
}
),
props => (props.src ? filter(props.src, props.data, '| raw') : undefined)
);
}
@autobind

View File

@ -10,7 +10,8 @@ import {
autobind,
createObject,
isObject,
isArrayChildrenModified
isArrayChildrenModified,
getPropValue
} from '../utils/helper';
import {Icon} from '../components/icons';
import {BaseSchema, SchemaCollection, SchemaName, SchemaTpl} from '../Schema';
@ -147,11 +148,7 @@ export class Carousel extends React.Component<CarouselProps, CarouselState> {
state = {
current: 0,
options:
this.props.options ||
this.props.value ||
resolveVariable(this.props.name, this.props.data) ||
[],
options: this.props.options || getPropValue(this.props) || [],
nextAnimation: ''
};
@ -162,16 +159,8 @@ export class Carousel extends React.Component<CarouselProps, CarouselState> {
componentDidUpdate(prevProps: CarouselProps) {
const props = this.props;
const nextOptions =
props.options ||
props.value ||
resolveVariable(props.name, props.data) ||
[];
const prevOptions =
prevProps.options ||
prevProps.value ||
resolveVariable(prevProps.name, prevProps.data) ||
[];
const nextOptions = props.options || getPropValue(props);
const prevOptions = prevProps.options || getPropValue(prevProps) || [];
if (isArrayChildrenModified(prevOptions, nextOptions)) {
this.setState({

View File

@ -4,6 +4,7 @@
import React from 'react';
import {Renderer, RendererProps} from '../factory';
import {BaseSchema} from '../Schema';
import {getPropValue} from '../utils/helper';
import {resolveVariableAndFilter} from '../utils/tpl-builtin';
/**
@ -39,17 +40,8 @@ export class ColorField extends React.Component<ColorProps, object> {
};
render() {
const {
className,
data,
classnames: cx,
name,
value,
defaultColor,
showValue
} = this.props;
const color =
value || (name ? resolveVariableAndFilter(name, data, '| raw') : null);
const {className, classnames: cx, defaultColor, showValue} = this.props;
const color = getPropValue(this.props);
return (
<div className={cx('ColorField', className)}>

View File

@ -2,6 +2,7 @@ import React from 'react';
import {Renderer, RendererProps} from '../factory';
import moment from 'moment';
import {BaseSchema} from '../Schema';
import {getPropValue} from '../utils/helper';
/**
* Date
@ -90,7 +91,6 @@ export class DateField extends React.Component<DateProps, DateState> {
render() {
const {
value,
valueFormat,
format,
placeholder,
@ -103,6 +103,8 @@ export class DateField extends React.Component<DateProps, DateState> {
<span className="text-muted">{placeholder}</span>
);
const value = getPropValue(this.props);
if (value) {
let ISODate = moment(value, moment.ISO_8601);
let NormalDate = moment(value, valueFormat);

View File

@ -2,7 +2,7 @@ import React from 'react';
import {Renderer, RendererProps} from '../factory';
import {Schema} from '../types';
import {resolveVariable} from '../utils/tpl-builtin';
import {createObject, isObject} from '../utils/helper';
import {createObject, getPropValue, isObject} from '../utils/helper';
import {BaseSchema, SchemaCollection} from '../Schema';
/**
@ -43,24 +43,23 @@ export default class Each extends React.Component<EachProps> {
name,
className,
render,
value,
defaultValue,
items,
placeholder,
classnames: cx,
translate: __
} = this.props;
const arr =
typeof value !== 'undefined'
? isObject(value)
? Object.keys(value).map(key => ({
key: key,
value: value[key]
}))
: Array.isArray(value)
? value
: []
: resolveVariable(name, data);
const value = getPropValue(this.props);
const arr = isObject(value)
? Object.keys(value).map(key => ({
key: key,
value: value[key]
}))
: Array.isArray(value)
? value
: [];
return (
<div className={cx('Each', className)}>

View File

@ -2,7 +2,7 @@ import React from 'react';
import {Renderer, RendererProps} from '../factory';
import {filter} from '../utils/tpl';
import {ClassNamesFn, themeable, ThemeProps} from '../theme';
import {autobind} from '../utils/helper';
import {autobind, getPropValue} from '../utils/helper';
import {Icon} from '../components/icons';
import {LocaleProps, localeable} from '../locale';
import {BaseSchema, SchemaClassName, SchemaTpl, SchemaUrlPath} from '../Schema';
@ -282,11 +282,7 @@ export class ImageField extends React.Component<ImageFieldProps, object> {
const finnalSrc = src ? filter(src, data, '| raw') : '';
let value =
finnalSrc ||
this.props.value ||
resolveVariable(name, data) ||
defaultImage ||
imagePlaceholder;
finnalSrc || getPropValue(this.props) || defaultImage || imagePlaceholder;
return (
<div className={cx('ImageField', className)}>

View File

@ -7,7 +7,7 @@ import {
resolveVariableAndFilter
} from '../utils/tpl-builtin';
import Image, {ImageThumbProps, imagePlaceholder} from './Image';
import {autobind} from '../utils/helper';
import {autobind, getPropValue} from '../utils/helper';
import {BaseSchema, SchemaClassName, SchemaUrlPath} from '../Schema';
/**
@ -166,12 +166,12 @@ export class ImagesField extends React.Component<ImagesProps> {
options
} = this.props;
let value = this.props.value ?? resolveVariable(name, data);
let value: any;
let list: any;
if (typeof source === 'string' && isPureVariable(source)) {
list = resolveVariableAndFilter(source, data, '| raw') || undefined;
} else if (Array.isArray(value)) {
} else if (Array.isArray((value = getPropValue(this.props)))) {
list = value;
} else if (Array.isArray(options)) {
list = options;

View File

@ -2,7 +2,7 @@ import React from 'react';
import {Renderer, RendererProps} from '../factory';
import JSONTree from 'react-json-tree';
import {autobind} from '../utils/helper';
import {autobind, getPropValue} from '../utils/helper';
import {BaseSchema} from '../Schema';
import {resolveVariableAndFilter, isPureVariable} from '../utils/tpl-builtin';
/**
@ -152,7 +152,6 @@ export class JSONField extends React.Component<JSONProps, object> {
render() {
const {
className,
value,
jsonTheme,
classnames: cx,
hideRoot,
@ -160,6 +159,8 @@ export class JSONField extends React.Component<JSONProps, object> {
source
} = this.props;
const value = getPropValue(this.props);
let data = value;
if (source !== undefined && isPureVariable(source)) {
data = resolveVariableAndFilter(source, this.props.data, '| raw');

View File

@ -1,6 +1,7 @@
import React from 'react';
import {Renderer, RendererProps} from '../factory';
import {BaseSchema, SchemaTpl} from '../Schema';
import {getPropValue} from '../utils/helper';
import {filter} from '../utils/tpl';
/**
@ -48,7 +49,7 @@ export class LinkField extends React.Component<LinkProps, object> {
title
} = this.props;
let value = this.props.value;
let value = getPropValue(this.props);
const finnalHref = href ? filter(href, data, '| raw') : '';
return (

View File

@ -12,7 +12,7 @@ import {
} from '../Schema';
import {withStore} from '../components/WithStore';
import {flow, Instance, types} from 'mobx-state-tree';
import {getVariable, guid, isObject} from '../utils/helper';
import {getPropValue, getVariable, guid, isObject} from '../utils/helper';
import {StoreNode} from '../store/node';
import isPlainObject from 'lodash/isPlainObject';
import {isPureVariable, resolveVariableAndFilter} from '../utils/tpl-builtin';
@ -187,8 +187,7 @@ export const MappingField = withStore(props =>
} = this.props;
const map = store.map;
let key =
this.props.value ?? (name ? getVariable(data, name) : undefined);
let key = getPropValue(this.props);
let viewValue: React.ReactNode = (
<span className="text-muted">{placeholder}</span>

View File

@ -6,6 +6,7 @@ import {Renderer, RendererProps} from '../factory';
import {BaseSchema} from '../Schema';
import {resolveVariableAndFilter} from '../utils/tpl-builtin';
import LazyComponent from '../components/LazyComponent';
import {getPropValue} from '../utils/helper';
/**
* Markdown
@ -43,9 +44,10 @@ export interface MarkdownProps
export class Markdown extends React.Component<MarkdownProps, object> {
render() {
const {className, data, classnames: cx, name, value} = this.props;
const {className, data, classnames: cx, name} = this.props;
const content =
value || (name ? resolveVariableAndFilter(name, data, '| raw') : null);
getPropValue(this.props) ||
(name ? resolveVariableAndFilter(name, data, '| raw') : null);
return (
<div className={cx('Markdown', className)}>

View File

@ -3,6 +3,7 @@ import {Renderer, RendererProps} from '../factory';
import {filter} from '../utils/tpl';
import cx from 'classnames';
import {BaseSchema, SchemaTpl} from '../Schema';
import {getPropValue} from '../utils/helper';
/**
* Plain
@ -47,7 +48,6 @@ export class Plain extends React.Component<PlainProps, object> {
const {
className,
wrapperComponent,
value,
text,
data,
tpl,
@ -56,6 +56,7 @@ export class Plain extends React.Component<PlainProps, object> {
classnames: cx
} = this.props;
const value = getPropValue(this.props);
const Component = wrapperComponent || (inline ? 'span' : 'div');
return (

View File

@ -5,6 +5,7 @@ import {Api, SchemaNode, PlainObject} from '../types';
import {filter} from '../utils/tpl';
import cx from 'classnames';
import {BaseSchema, SchemaClassName} from '../Schema';
import {getPropValue} from '../utils/helper';
/**
*
@ -91,7 +92,7 @@ export class ProgressField extends React.Component<ProgressProps, object> {
classnames: cx
} = this.props;
let value = this.props.value;
let value = getPropValue(this.props);
let viewValue: React.ReactNode = (
<span className="text-muted">{placeholder}</span>
);

View File

@ -75,11 +75,12 @@ export default class QRCode extends React.Component<QRCodeProps, any> {
placeholder,
level,
value,
defaultValue,
data,
classPrefix: ns
} = this.props;
const finalValue = filter(value, data, '| raw');
const finalValue = value || filter(defaultValue, data, '| raw');
return (
<div className={cx(`${ns}QrCode`, className)}>

View File

@ -3,7 +3,12 @@ import {Renderer, RendererProps} from '../factory';
import React from 'react';
import {BaseSchema, SchemaClassName} from '../Schema';
import SearchBox from '../components/SearchBox';
import {autobind, getVariable, setVariable} from '../utils/helper';
import {
autobind,
getPropValue,
getVariable,
setVariable
} from '../utils/helper';
/**
*
@ -67,7 +72,7 @@ export class SearchBoxRenderer extends React.Component<SearchBoxProps> {
handleCancel() {
const name = this.props.name;
const onQuery = this.props.onQuery;
const value = this.props.value ?? getVariable(this.props.data, name);
const value = getPropValue(this.props);
if (value !== '') {
const data: any = {};
setVariable(data, name, '');
@ -95,7 +100,7 @@ export class SearchBoxRenderer extends React.Component<SearchBoxProps> {
className
} = this.props;
const value = this.props.value ?? getVariable(data, name);
const value = getPropValue(this.props);
return (
<SearchBox

View File

@ -4,7 +4,7 @@ import React from 'react';
import {resolveVariableAndFilter} from '../utils/tpl-builtin';
import {BaseSchema, SchemaClassName} from '../Schema';
import {ActionSchema} from './Action';
import {autobind, createObject} from '../utils/helper';
import {autobind, createObject, getPropValue} from '../utils/helper';
export interface SparkLineSchema extends BaseSchema {
type: 'sparkline';
@ -91,9 +91,7 @@ export class SparkLineRenderer extends React.Component<SparkLineRendProps> {
render() {
const {value, name, data, clickAction} = this.props;
const finalValue =
value ?? (name ? resolveVariableAndFilter(name, data) : [1, 1]);
const finalValue = getPropValue(this.props) || [1, 1];
return (
<SparkLine

View File

@ -6,6 +6,7 @@ import {filter} from '../utils/tpl';
import cx from 'classnames';
import {Icon} from '../components/icons';
import {BaseSchema} from '../Schema';
import {getPropValue} from '../utils/helper';
/**
*
@ -89,7 +90,7 @@ export class StatusField extends React.Component<StatusProps, object> {
classnames: cx,
data
} = this.props;
let value = this.props.value;
let value = getPropValue(this.props);
let viewValue: React.ReactNode = (
<span className="text-muted">{placeholder}</span>
);

View File

@ -8,6 +8,7 @@ import {
} from '../components/WithRemoteConfig';
import {resolveVariable} from '../utils/tpl-builtin';
import {filter} from '../utils/tpl';
import {getPropValue} from '../utils/helper';
enum StepStatus {
wait = 'wait',
@ -87,7 +88,6 @@ export function Steps(props: StepsProps) {
className,
classnames: cx,
steps,
value = 0,
status,
data,
source,
@ -98,6 +98,8 @@ export function Steps(props: StepsProps) {
config ||
steps ||
[];
const value = getPropValue(props) ?? 0;
const resolveValue =
typeof value === 'string' && isNaN(+value)
? (resolveVariable(value, data) as string) || +value

View File

@ -2,7 +2,7 @@ import React from 'react';
import {Renderer, RendererProps} from '../factory';
import {filter} from '../utils/tpl';
import cx from 'classnames';
import {anyChanged} from '../utils/helper';
import {anyChanged, getPropValue} from '../utils/helper';
import {escapeHtml} from '../utils/tpl-builtin';
import {BaseSchema, SchemaTpl} from '../Schema';
@ -74,7 +74,8 @@ export class Tpl extends React.Component<TplProps, object> {
}
getContent() {
const {tpl, html, text, raw, value, data, placeholder} = this.props;
const {tpl, html, text, raw, data, placeholder} = this.props;
const value = getPropValue(this.props);
if (raw) {
return raw;

View File

@ -150,7 +150,7 @@ export function findIndex(
export function getVariable(
data: {[propName: string]: any},
key: string,
key: string | undefined,
canAccessSuper: boolean = true
): any {
if (!data || !key) {
@ -1528,3 +1528,49 @@ export function getScrollbarWidth() {
return scrollbarWidth;
}
// 统一的获取 value 值方法
export function getPropValue<
T extends {
value?: any;
name?: string;
data?: any;
defaultValue?: any;
}
>(props: T, getter?: (props: T) => any) {
const {name, value, data, defaultValue} = props;
return value ?? getter?.(props) ?? getVariable(data, name) ?? defaultValue;
}
// 检测 value 是否有变化,有变化就执行 onChange
export function detectPropValueChanged<
T extends {
value?: any;
name?: string;
data?: any;
defaultValue?: any;
}
>(
props: T,
prevProps: T,
onChange: (value: any) => void,
getter?: (props: T) => any
) {
let nextValue: any;
if (props.value !== prevProps.value) {
onChange(props.value);
} else if (
(nextValue = getter?.(props)) !== undefined &&
nextValue !== getter!(prevProps)
) {
onChange(nextValue);
} else if (
typeof props.name === 'string' &&
(nextValue = getVariable(props.data, props.name)) !== undefined &&
nextValue !== getVariable(prevProps.data, prevProps.name)
) {
onChange(nextValue);
} else if (props.defaultValue !== prevProps.defaultValue) {
onChange(props.defaultValue);
}
}