|
|
@@ -30,17 +30,6 @@ const filterArrayByIndex = (array: any[], index: number) => array.filter((item,
|
|
|
|
|
|
const getUuidByArray = (array: any[]) => array.map(() => getUuidv4());
|
|
|
|
|
|
-// const getUpdateKey = (arrayField: ArrayFieldStaff): string | undefined => {
|
|
|
-// if (!arrayField) {
|
|
|
-// return undefined;
|
|
|
-// }
|
|
|
-// // TODO
|
|
|
-// if (arrayField && arrayField.updateKey) {
|
|
|
-// return arrayField.updateKey;
|
|
|
-// }
|
|
|
-// return undefined;
|
|
|
-// };
|
|
|
-
|
|
|
const initValueAdapter = (initValue: any) => {
|
|
|
const iv: any[] = [];
|
|
|
if (Array.isArray(initValue)) {
|
|
|
@@ -60,14 +49,23 @@ const initValueAdapter = (initValue: any) => {
|
|
|
* @param {string[]} oldKeys
|
|
|
* @param {any[]} cacheValue
|
|
|
* @returns string[]
|
|
|
+ *
|
|
|
+ * 2 -> 3,理想情况,看加的哪个,复用2个
|
|
|
+ * 3 -> 2, 理想情况,看删的哪个,减少,
|
|
|
+ * 2 -> 2, 看值变不变
|
|
|
+ * 嵌套场景,外部变不变无所谓,里面尽量不变,否则会走卸载。除非判断出嵌套时候
|
|
|
+ * 外部 setValue、setValues 变更,不易判断改的是哪行
|
|
|
+ * 如果只有自己一层,那都变问题也不大。如果有两层以上,变就会导致里面一层卸载再挂载。
|
|
|
*/
|
|
|
+
|
|
|
const generateKeys = (value: any[] = [], oldKeys?: string[], cacheValues: any[] = []) => {
|
|
|
const val = initValueAdapter(value);
|
|
|
const newKeys = getUuidByArray(val);
|
|
|
- const keys = [];
|
|
|
+ // const keys = newKeys.map((key, i) => (oldKeys && oldKeys[i] ? oldKeys[i] : key));
|
|
|
|
|
|
- // todo cacheValue 与 oldKeys 是对不上的
|
|
|
+ const keys = [];
|
|
|
|
|
|
+ // Keys 的复用机制需要
|
|
|
value.forEach((newRow, i) => {
|
|
|
const cacheRow = get(cacheValues, i);
|
|
|
if (!isEqual(newRow, cacheRow)) {
|
|
|
@@ -75,17 +73,15 @@ const generateKeys = (value: any[] = [], oldKeys?: string[], cacheValues: any[]
|
|
|
} else {
|
|
|
keys[i] = oldKeys && oldKeys[i] ? oldKeys[i] : newKeys[i];
|
|
|
}
|
|
|
-
|
|
|
});
|
|
|
+
|
|
|
return keys;
|
|
|
};
|
|
|
|
|
|
class ArrayFieldComponent extends Component<ArrayFieldProps, ArrayFieldState> {
|
|
|
static contextType = FormUpdaterContext;
|
|
|
|
|
|
- cacheFieldValues: any[] | null;
|
|
|
- shouldUseInitValue: boolean;
|
|
|
- // cacheUpdateKey: string;
|
|
|
+ hasMounted: boolean;
|
|
|
context: FormUpdaterContextType;
|
|
|
|
|
|
constructor(props: ArrayFieldProps, context: FormUpdaterContextType) {
|
|
|
@@ -94,20 +90,20 @@ class ArrayFieldComponent extends Component<ArrayFieldProps, ArrayFieldState> {
|
|
|
const { field } = this.props;
|
|
|
const initValueInForm = context.getValue(field);
|
|
|
const initValue = initValueInProps || initValueInForm;
|
|
|
+
|
|
|
+ this.hasMounted = Boolean(context.getArrayField(field));
|
|
|
+
|
|
|
this.state = {
|
|
|
keys: generateKeys(initValue),
|
|
|
};
|
|
|
this.add = this.add.bind(this);
|
|
|
this.addWithInitValue = this.addWithInitValue.bind(this);
|
|
|
this.remove = this.remove.bind(this);
|
|
|
- this.cacheFieldValues = initValue;
|
|
|
-
|
|
|
// /*
|
|
|
// If updateKey exists, it means that the arrayField (usually a nested ArrayField not at the first level) is only re-mounted due to setValues,
|
|
|
// and the fields it contains do not need to consume initValue
|
|
|
// */
|
|
|
// // whether the fields inside arrayField should use props.initValue in current render process
|
|
|
- // this.shouldUseInitValue = !context.getArrayField(field);
|
|
|
|
|
|
// Separate the arrays that reset and the usual add and remove modify, otherwise they will affect each other
|
|
|
const initValueCopyForFormState = cloneDeep(initValue);
|
|
|
@@ -117,49 +113,57 @@ class ArrayFieldComponent extends Component<ArrayFieldProps, ArrayFieldState> {
|
|
|
}
|
|
|
|
|
|
componentDidMount() {
|
|
|
- // const { field } = this.props;
|
|
|
- // const updater = this.context;
|
|
|
- // updater.updateArrayField(field, { forceUpdate: this.forceUpdate });
|
|
|
+ const { field } = this.props;
|
|
|
+ const initValueInArrayFieldProps = this.props.initValue;
|
|
|
+ const updater = this.context;
|
|
|
+
|
|
|
+ const formProps = updater.getFormProps(['initValues']);
|
|
|
+ const initValueInFormProps = get(formProps, field);
|
|
|
+
|
|
|
+ const initValueInFormState = updater.getValue(field);
|
|
|
+
|
|
|
+ const initValue = initValueInArrayFieldProps || initValueInFormProps || initValueInFormState;
|
|
|
+
|
|
|
+ const initValueCopyForFormState = cloneDeep(initValue);
|
|
|
+ const initValueCopyForReset = cloneDeep(initValue);
|
|
|
+
|
|
|
+ // 如果首次挂载,应该使用初始值,如果不是首次挂载,例如嵌套场景下,level 1 keys变更导致的 level 2子级重新挂载,那应该直接使用formState 中的值 , 且无需注册 initValue(否则会影响保存的 initValue)
|
|
|
+ if (!this.hasMounted) {
|
|
|
+ updater.registerArrayField(field, { initValue: initValueCopyForReset, forceUpdate: this.forceKeysUpdate });
|
|
|
+ updater.updateStateValue(field, initValueCopyForFormState, { notNotify: true, notUpdate: true });
|
|
|
+ } else {
|
|
|
+ if (field === 'data[0].rules') {
|
|
|
+ const a = updater.getArrayField();
|
|
|
+ console.log('data[0].rules didmount');
|
|
|
+ }
|
|
|
+ updater.registerArrayField(field, { forceUpdate: this.forceKeysUpdate });
|
|
|
+ }
|
|
|
+ console.log('didMount', this.props.field);
|
|
|
}
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
const updater = this.context;
|
|
|
const { field } = this.props;
|
|
|
+ // 卸载时,不卸载 initValue?
|
|
|
+ // 嵌套的不做卸载?
|
|
|
updater.unRegisterArrayField(field);
|
|
|
+ console.log('unmount', this.props.field);
|
|
|
}
|
|
|
|
|
|
- // componentDidUpdate() {
|
|
|
- // const updater = this.context;
|
|
|
- // // const { field } = this.props;
|
|
|
- // // const { keys } = this.state;
|
|
|
- // // const fieldValues = updater.getValue(field);
|
|
|
- // // const updateKey = getUpdateKey(updater.getArrayField(field));
|
|
|
- // // // when update form outside, like use formApi.setValue('field', [{newItem1, newItem2}]), formApi.setValues
|
|
|
- // // // re generate keys to update arrayField;
|
|
|
- // // if (updateKey !== this.cacheUpdateKey) {
|
|
|
- // // const newKeys = generateKeys(fieldValues, keys);
|
|
|
- // // // eslint-disable-next-line
|
|
|
- // // this.setState({ keys: newKeys });
|
|
|
- // // this.cacheUpdateKey = updateKey;
|
|
|
- // // if (this.cacheUpdateKey !== null) {
|
|
|
- // // this.shouldUseInitValue = false;
|
|
|
- // // }
|
|
|
- // // } else {
|
|
|
- // // console.log('not update');
|
|
|
- // // }
|
|
|
- // }
|
|
|
-
|
|
|
- forceUpdate = (value?: any): void => {
|
|
|
+ forceKeysUpdate = ({ newValue, oldValue }): void => {
|
|
|
const updater = this.context;
|
|
|
const { field } = this.props;
|
|
|
const { keys } = this.state;
|
|
|
- console.log(this.cacheFieldValues);
|
|
|
- const fieldValues = value ? value : updater.getValue(field);
|
|
|
- // TODO fieldValues 如果长度相同,keys目前仍会相同,需要为新的
|
|
|
- const newKeys = generateKeys(fieldValues, keys, this.cacheFieldValues);
|
|
|
+
|
|
|
+ const fieldValues = newValue ? newValue : updater.getValue(field);
|
|
|
+ const newKeys = generateKeys(fieldValues, keys, oldValue);
|
|
|
+ // const newKeys = generateKeys(fieldValues, keys, this.cacheFieldValues);
|
|
|
+
|
|
|
// eslint-disable-next-line
|
|
|
this.setState({ keys: newKeys });
|
|
|
- this.cacheFieldValues = [...value];
|
|
|
+ // A: A1、A2 -> A: A1-new -> A: A1、A2
|
|
|
+ // 如果 forecUpdate child,改变了 child 的length,但是这个无法更新父级的 cacheFieldValue。会有问题, cache不是一个好的设计,要做完善还得在 setValue时检测潜在的对父子 cacheValue的影响
|
|
|
+ // this.cacheFieldValues = cloneDeep(value);
|
|
|
}
|
|
|
|
|
|
add() {
|
|
|
@@ -204,7 +208,7 @@ class ArrayFieldComponent extends Component<ArrayFieldProps, ArrayFieldState> {
|
|
|
updater.updateStateValue(field, newArrayFieldValue);
|
|
|
}
|
|
|
this.setState({ keys: newKeys });
|
|
|
- this.cacheFieldValues = [...newArrayFieldValue];
|
|
|
+ // this.cacheFieldValues = cloneDeep(newArrayFieldValue);
|
|
|
}
|
|
|
|
|
|
render() {
|
|
|
@@ -218,6 +222,7 @@ class ArrayFieldComponent extends Component<ArrayFieldProps, ArrayFieldState> {
|
|
|
const { add } = this;
|
|
|
const { addWithInitValue } = this;
|
|
|
const contextVal = {
|
|
|
+ isInArrayField: true,
|
|
|
// shouldUseInitValue: this.shouldUseInitValue,
|
|
|
};
|
|
|
return (
|