Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion examples/StateForm-basic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ export default class Demo extends React.Component {
<Field dependencies={['username']}>
{(control, meta, context) => {
const { username } = context.getFieldsValue();
return username === '111' ? <Input {...control} placeholder="I am secret!" /> : null;
console.log('my render!', username);
return username === '111' && <Input {...control} placeholder="I am secret!" />;
}}
</Field>

Expand Down
14 changes: 14 additions & 0 deletions src/Field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,20 @@ class Field extends React.Component<FieldProps, FieldState> implements FieldEnti
break;
}

case 'dependenciesUpdate': {
/**
* Trigger when marked `dependencies` updated. Related fields will all update
*/
const dependencyList = dependencies.map(getNamePath);
if (
(namePathList && containsNamePath(namePathList, namePath)) ||
dependencyList.some(dependency => containsNamePath(info.relatedFields, dependency))
) {
this.forceUpdate();
}
break;
}

default:
/**
* - If `namePath` exists in `namePathList`, means it's related value and should update.
Expand Down
9 changes: 9 additions & 0 deletions src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,15 @@ export type NotifyInfo =
| {
type: 'setField';
data: FieldData;
}
| {
type: 'dependenciesUpdate';
/**
* Contains all the related `InternalNamePath[]`.
* a <- b <- c : change `a`
* relatedFields=[a, b, c]
*/
relatedFields: InternalNamePath[];
};

export interface Callbacks {
Expand Down
5 changes: 5 additions & 0 deletions src/useForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,11 @@ export class FormStore {
const childrenFields = this.getDependencyChildrenFields(namePath);
this.validateFields(childrenFields);

this.notifyObservers(prevStore, childrenFields, {
type: 'dependenciesUpdate',
relatedFields: [namePath, ...childrenFields],
});

// trigger callback function
const { onValuesChange } = this.callbacks;

Expand Down
8 changes: 3 additions & 5 deletions tests/common/InfoField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,16 @@ interface InfoFieldProps extends FieldProps {
children: ReactElement;
}

export const Input = ({ value = '', ...props }) => <input {...props} value={value} />;

/**
* Return a wrapped Field with meta info
*/
const InfoField: React.FC<InfoFieldProps> = ({ children, ...props }) => (
<Field {...props}>
{(control, { errors }) => (
<div>
{children ? (
React.cloneElement(children, control)
) : (
<input {...control} value={control.value || ''} />
)}
{children ? React.cloneElement(children, control) : <Input {...control} />}
<ul className="errors">
{errors.map(error => (
<li key={error}>{error}</li>
Expand Down
6 changes: 5 additions & 1 deletion tests/common/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import timeout from './timeout';
import InfoField from './InfoField';
import InfoField, { Input } from './InfoField';

export async function changeValue(wrapper, value) {
wrapper.find('input').simulate('change', { target: { value } });
Expand All @@ -22,3 +22,7 @@ export function matchError(wrapper, error) {
export function getField(wrapper, index = 0) {
return wrapper.find(InfoField).at(index);
}

export function getInput(wrapper, index = 0) {
return wrapper.find(Input).at(index);
}
45 changes: 42 additions & 3 deletions tests/dependencies.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';
import { mount } from 'enzyme';
import Form from '../src';
import InfoField from './common/InfoField';
import { changeValue, matchError, getField } from './common';
import Form, { Field } from '../src';
import InfoField, { Input } from './common/InfoField';
import { changeValue, matchError, getField, getInput } from './common';

describe('dependencies', () => {
it('touched', async () => {
Expand Down Expand Up @@ -30,4 +30,43 @@ describe('dependencies', () => {
await changeValue(getField(wrapper, 0), '');
matchError(getField(wrapper, 1), true);
});

it('nest dependencies', async () => {
let form = null;
let rendered = false;

const wrapper = mount(
<div>
<Form
ref={instance => {
form = instance;
}}
>
<Field name="field_1">
<Input />
</Field>
<Field name="field_2" dependencies={['field_1']}>
<Input />
</Field>
<Field name="field_3" dependencies={['field_2']}>
{control => {
rendered = true;
return <Input {...control} />;
}}
</Field>
</Form>
</div>,
);

form.setFields([
{ name: 'field_1', touched: true },
{ name: 'field_2', touched: true },
{ name: 'field_3', touched: true },
]);

rendered = false;
await changeValue(getInput(wrapper), '1');

expect(rendered).toBeTruthy();
});
});