react-native-simple-form
Version:
Form library for react-native to make forms easier.
207 lines (180 loc) • 4.8 kB
JavaScript
import React from 'react';
import { View } from 'react-native';
import _ from 'lodash';
export default class Form extends React.Component {
/**
* @param {Object} props
*/
constructor(props) {
super(props);
this.fields = {};
this.formFields = {};
}
/**
* @private
* @param {String} id
* @param {String} name
* @param {String} value
*/
_persistFieldValue(id, name, value) {
this.fields[id] = { name, value };
}
/**
* @returns {Object}
*/
getValues() {
let fieldsArray = [];
Object.keys(this.fields).map((id, index) => {
fieldsArray[index] = this.fields[id];
});
return _.transform(
fieldsArray,
function(result, item, key) {
result[item.name] = item.value;
},
{}
);
}
/**
* @private
* @param {String} id
* @param {String} name
* @param {String} ref
*/
_persistFieldRef(id, name, value) {
this.formFields[id] = { name, value };
}
/**
* @returns {Object}
*/
getRefs() {
let fieldsArray = [];
Object.keys(this.formFields).map((id, index) => {
var tempRef = Object.assign({}, this.formFields[id]);
var _refs = this.refs;
// value 其实就是 ref 参数的名字 // value actually is 'ref'
tempRef.name = tempRef.value; // 这里其实只用value // here just same as the value
tempRef.value = _refs[tempRef.value]; // 这里获得对应的ref // here get the ref
fieldsArray[index] = tempRef;
});
return serialize(fieldsArray);
}
/**
* @returns {Object}
*/
_getAllowedFormFieldTypes() {
return {
TextInput: {
defaultValue: '',
valueProp: 'defaultValue',
callbackProp: 'onChangeText'
},
Switch: {
controlled: true,
valueProp: 'value',
callbackProp: 'onValueChange'
},
SliderIOS: {
valueProp: 'value',
callbackProp: 'onSlidingComplete'
},
Slider: {
valueProp: 'value',
callbackProp: 'onSlidingComplete'
},
Picker: {
controlled: true,
valueProp: 'selectedValue',
callbackProp: 'onValueChange'
},
PickerIOS: {
controlled: true,
valueProp: 'selectedValue',
callbackProp: 'onValueChange'
},
DatePickerIOS: {
controlled: true,
valueProp: 'date',
callbackProp: 'onDateChange'
}
};
}
/**
* @return [ReactComponent]
*/
_createFormFields(elements) {
const allowedFieldTypes = this._getAllowedFormFieldTypes();
return React.Children.map(elements, (element, fieldIndex) => {
if (typeof element !== 'object') {
return element;
}
const fieldType = element.props.type;
const fieldName = element.props.name;
const allowedField = allowedFieldTypes[fieldType];
const isValidField = !!(allowedField && fieldName);
const fieldId = fieldName + element.key;
let props = {};
if (fieldName) {
// set refs
if (!this.formFields[fieldId]) {
this._persistFieldRef(
fieldId,
fieldName,
element.ref || element.props.name || fieldName
);
}
props.ref = this.formFields[fieldId].value;
}
// binding values changed
if (!isValidField) {
if (fieldType == 'Accordion') {
return React.cloneElement(element, {
...props,
children: this._createFormFields(element.props.content)
});
} else {
return React.cloneElement(element, {
...props,
children: this._createFormFields(element.props.children)
});
}
}
props[allowedField.callbackProp] = value => {
this._persistFieldValue(fieldId, fieldName, value);
if (allowedField.controlled) {
this.forceUpdate();
}
const proxyCallback = element.props[allowedField.callbackProp];
if (typeof proxyCallback === 'function') {
proxyCallback(value);
}
};
if (!this.fields[fieldId]) {
this._persistFieldValue(
fieldId,
fieldName,
element.props[allowedField.valueProp] ||
element.props.value ||
allowedField.defaultValue
);
}
if (allowedField.controlled) {
props[allowedField.valueProp] = this.fields[fieldId].value;
}
return React.cloneElement(element, {
...props,
children: this._createFormFields(element.props.children)
});
});
}
/**
* @returns {ReactComponent}
*/
render() {
return (
<View {...this.props}>
{this._createFormFields(this.props.children)}
</View>
);
}
}