From 0c83e671929fc8101cbfd9ba6e5229b52b2ece9b Mon Sep 17 00:00:00 2001 From: zombiej Date: Fri, 14 Aug 2020 14:10:43 +0800 Subject: [PATCH 1/2] fix: Form preserve should not work on Form.List Item --- examples/list.tsx | 3 +++ src/Field.tsx | 16 +++++++-------- src/useForm.ts | 4 ++-- tests/preserve.test.tsx | 43 +++++++++++++++++++++++++++++++++++++++-- 4 files changed, 54 insertions(+), 12 deletions(-) diff --git a/examples/list.tsx b/examples/list.tsx index 6dc84227..76a08a78 100644 --- a/examples/list.tsx +++ b/examples/list.tsx @@ -21,7 +21,10 @@ const Demo = () => { console.log('values:', values); }} style={{ border: '1px solid red', padding: 15 }} + preserve={false} > + {() => JSON.stringify(form.getFieldsValue(), null, 2)} + {(fields, { add, remove }) => { console.log('Demo Fields:', fields); diff --git a/src/Field.tsx b/src/Field.tsx index 0c8f534b..0cfe4a9c 100644 --- a/src/Field.tsx +++ b/src/Field.tsx @@ -73,13 +73,13 @@ export interface InternalFieldProps { initialValue?: any; onReset?: () => void; preserve?: boolean; + + /** @private Passed by Form.List props. Do not use since it will break by path check. */ + isListField?: boolean; } export interface FieldProps extends Omit { name?: NamePath; - - /** @private Passed by Form.List props. */ - isListField?: boolean; } export interface FieldState { @@ -102,7 +102,7 @@ class Field extends React.Component void | null = null; + private cancelRegisterFunc: (isListField?: boolean, preserve?: boolean) => void | null = null; private destroy = false; @@ -140,10 +140,10 @@ class Field extends React.Component { - const { preserve } = this.props; + const { preserve, isListField } = this.props; if (this.cancelRegisterFunc) { - this.cancelRegisterFunc(preserve); + this.cancelRegisterFunc(isListField, preserve); } this.cancelRegisterFunc = null; }; @@ -498,11 +498,11 @@ class Field extends React.Component = ({ name, isListField, ...restProps }) => { +const WrapperField: React.FC = ({ name, ...restProps }) => { const namePath = name !== undefined ? getNamePath(name) : undefined; let key: string = 'keep'; - if (!isListField) { + if (!restProps.isListField) { key = `_${(namePath || []).join('_')}`; } return ; diff --git a/src/useForm.ts b/src/useForm.ts index 94e6a73f..a0aa8eef 100644 --- a/src/useForm.ts +++ b/src/useForm.ts @@ -493,12 +493,12 @@ export class FormStore { } // un-register field callback - return (preserve?: boolean) => { + return (isListField?: boolean, preserve?: boolean) => { this.fieldEntities = this.fieldEntities.filter(item => item !== entity); // Clean up store value if preserve const mergedPreserve = preserve !== undefined ? preserve : this.preserve; - if (mergedPreserve === false) { + if (mergedPreserve === false && !isListField) { const namePath = entity.getNamePath(); if (this.getFieldValue(namePath) !== undefined) { this.store = setValue(this.store, namePath, undefined); diff --git a/tests/preserve.test.tsx b/tests/preserve.test.tsx index 7b8e4a6d..e98f34e2 100644 --- a/tests/preserve.test.tsx +++ b/tests/preserve.test.tsx @@ -1,7 +1,7 @@ -/* eslint-disable no-template-curly-in-string */ +/* eslint-disable no-template-curly-in-string, arrow-body-style */ import React from 'react'; import { mount } from 'enzyme'; -import Form from '../src'; +import Form, { FormInstance } from '../src'; import InfoField from './common/InfoField'; import timeout from './common/timeout'; @@ -74,5 +74,44 @@ describe('Form.Preserve', () => { await matchTest(true, { keep: 233 }); await matchTest(false, { keep: 233, remove: 666 }); }); + + it('form perishable should not crash Form.List', async () => { + let form: FormInstance; + + const wrapper = mount( +
{ + form = instance; + }} + > + + {(fields, { remove }) => { + return ( +
+ {fields.map(field => ( + + + + ))} +
+ ); + }} +
+
, + ); + + wrapper.find('button').simulate('click'); + wrapper.update(); + + expect(form.getFieldsValue()).toEqual({ list: ['bamboo', 'little'] }); + }); }); /* eslint-enable no-template-curly-in-string */ From 31b67ba0b24915839797c6befc2e7158b2b559a9 Mon Sep 17 00:00:00 2001 From: zombiej Date: Fri, 14 Aug 2020 14:19:20 +0800 Subject: [PATCH 2/2] add warning --- src/Field.tsx | 8 ++++++++ tests/preserve.test.tsx | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/Field.tsx b/src/Field.tsx index 0cfe4a9c..44ca5f69 100644 --- a/src/Field.tsx +++ b/src/Field.tsx @@ -505,6 +505,14 @@ const WrapperField: React.FC = ({ name, ...restProps }) => { if (!restProps.isListField) { key = `_${(namePath || []).join('_')}`; } + + if (process.env.NODE_ENV !== 'production') { + warning( + restProps.preserve !== false || !restProps.isListField, + '`preserve` should not apply on Form.List fields.', + ); + } + return ; }; diff --git a/tests/preserve.test.tsx b/tests/preserve.test.tsx index e98f34e2..f3a18293 100644 --- a/tests/preserve.test.tsx +++ b/tests/preserve.test.tsx @@ -113,5 +113,29 @@ describe('Form.Preserve', () => { expect(form.getFieldsValue()).toEqual({ list: ['bamboo', 'little'] }); }); + + it('warning when Form.List use preserve', () => { + const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + + mount( +
+ + {fields => + fields.map(field => ( + + + + )) + } + +
, + ); + + expect(errorSpy).toHaveBeenCalledWith( + 'Warning: `preserve` should not apply on Form.List fields.', + ); + + errorSpy.mockRestore(); + }); }); /* eslint-enable no-template-curly-in-string */