diff --git a/README.md b/README.md
index 5eae3b63..117b0935 100644
--- a/README.md
+++ b/README.md
@@ -75,7 +75,8 @@ We use typescript to create the Type definition. You can view directly in IDE. B
| Prop | Description | Type | Default |
| --- | --- | --- | --- |
-| name | Field name path | [NamePath](#namepath)[] | - |
+| dependencies | Will re-render if dependencies changed | [NamePath](#namepath)[] | - |
+| name | Field name path | [NamePath](#namepath) | - |
| rules | Validate rules | [Rule](#rule)[] | - |
| shouldUpdate | Check if Field should update | (prevValues, nextValues): boolean | - |
| trigger | Collect value update by event trigger | string | onChange |
diff --git a/examples/StateForm-basic.tsx b/examples/StateForm-basic.tsx
index df68c7d9..c6745840 100644
--- a/examples/StateForm-basic.tsx
+++ b/examples/StateForm-basic.tsx
@@ -35,7 +35,7 @@ export default class Demo extends React.Component {
Show additional field when `username` is `111`
- prev.username !== next.username}>
+
{(control, meta, context) => {
const { username } = context.getFieldsValue();
return username === '111' ? : null;
diff --git a/package.json b/package.json
index 56db8736..bbb0d89c 100644
--- a/package.json
+++ b/package.json
@@ -42,6 +42,7 @@
"devDependencies": {
"@types/react": "^16.8.19",
"@types/react-dom": "^16.8.4",
+ "@types/warning": "^3.0.0",
"enzyme": "^3.1.0",
"enzyme-adapter-react-16": "^1.0.2",
"enzyme-to-json": "^3.1.4",
@@ -50,7 +51,6 @@
"react-dom": "^16.8.6",
"react-redux": "^4.4.10",
"react-router": "^3.0.0",
- "react-test-renderer": "^16.1.1",
"redux": "^3.7.2"
},
"pre-commit": [
@@ -58,7 +58,6 @@
],
"dependencies": {
"async-validator": "^1.11.2",
- "babel-runtime": "6.x",
"lodash": "^4.17.4",
"rc-util": "^4.6.0",
"warning": "^4.0.3"
diff --git a/src/Field.tsx b/src/Field.tsx
index 8a3f529d..654847ca 100644
--- a/src/Field.tsx
+++ b/src/Field.tsx
@@ -36,7 +36,10 @@ export interface FieldProps {
| React.ReactElement
| ((control: ChildProps, meta: Meta, form: FormInstance) => React.ReactNode);
rules?: Rule[];
- /** Set up `dependencies` field. When dependencies field update and current field is touched, will trigger validate rules. */
+ /**
+ * Set up `dependencies` field.
+ * When dependencies field update and current field is touched, will trigger validate rules and render.
+ */
dependencies?: NamePath[];
trigger?: string;
validateTrigger?: string | string[];
@@ -123,7 +126,7 @@ class Field extends React.Component implements FieldEnti
namePathList: InternalNamePath[] | null,
info: NotifyInfo,
) => {
- const { shouldUpdate } = this.props;
+ const { shouldUpdate, dependencies = [] } = this.props;
const { getFieldsValue, getFieldError }: FormInstance = this.context;
const values = getFieldsValue();
const namePath = this.getNamePath();
@@ -169,11 +172,15 @@ class Field extends React.Component implements FieldEnti
default:
/**
* - If `namePath` exists in `namePathList`, means it's related value and should update.
+ * - If `dependencies` exists in `namePathList`, means upstream trigger update.
* - If `shouldUpdate` provided, use customize logic to update the field
* - else to check if value changed
*/
if (
(namePathList && containsNamePath(namePathList, namePath)) ||
+ dependencies.some(dependency =>
+ containsNamePath(namePathList, getNamePath(dependency)),
+ ) ||
(shouldUpdate ? shouldUpdate(prevStore, values, info) : prevValue !== curValue)
) {
this.forceUpdate();
@@ -327,7 +334,8 @@ class Field extends React.Component implements FieldEnti
const { child, isFunction } = this.getOnlyChild(children);
if (!child) {
- return children;
+ // Return origin `children` if is not a function
+ return isFunction ? child : children;
}
// Not need to `cloneElement` since user can handle this in render function self
diff --git a/src/useForm.ts b/src/useForm.ts
index 146e9aa7..fa6bf91a 100644
--- a/src/useForm.ts
+++ b/src/useForm.ts
@@ -324,7 +324,7 @@ export class FormStore {
onValuesChange(changedValues, this.store);
}
- this.triggerOnFieldsChange([namePath]);
+ this.triggerOnFieldsChange([namePath, ...childrenFields]);
};
// Let all child Field get update.
@@ -365,8 +365,8 @@ export class FormStore {
if (!children.has(field)) {
children.add(field);
- if (field.isFieldTouched()) {
- const fieldNamePath = field.getNamePath();
+ const fieldNamePath = field.getNamePath();
+ if (field.isFieldTouched() && fieldNamePath.length) {
childrenFields.push(fieldNamePath);
fillChildren(fieldNamePath);
}
diff --git a/tests/common/index.js b/tests/common/index.js
index df37b29b..477f5174 100644
--- a/tests/common/index.js
+++ b/tests/common/index.js
@@ -1,4 +1,5 @@
import timeout from './timeout';
+import InfoField from './InfoField';
export async function changeValue(wrapper, value) {
wrapper.find('input').simulate('change', { target: { value } });
@@ -17,3 +18,7 @@ export function matchError(wrapper, error) {
expect(wrapper.find('.errors li').text()).toBe(error);
}
}
+
+export function getField(wrapper, index = 0) {
+ return wrapper.find(InfoField).at(index);
+}
diff --git a/tests/dependencies.test.js b/tests/dependencies.test.js
new file mode 100644
index 00000000..1033c60b
--- /dev/null
+++ b/tests/dependencies.test.js
@@ -0,0 +1,33 @@
+import React from 'react';
+import { mount } from 'enzyme';
+import Form from '../src';
+import InfoField from './common/InfoField';
+import { changeValue, matchError, getField } from './common';
+
+describe('dependencies', () => {
+ it('touched', async () => {
+ let form = null;
+
+ const wrapper = mount(
+
+
+
,
+ );
+
+ // Not trigger if not touched
+ await changeValue(getField(wrapper, 0), '');
+ matchError(getField(wrapper, 1), false);
+
+ // Trigger if touched
+ form.setFields([{ name: 'field_2', touched: true }]);
+ await changeValue(getField(wrapper, 0), '');
+ matchError(getField(wrapper, 1), true);
+ });
+});