Skip to content
This repository was archived by the owner on Aug 23, 2022. It is now read-only.

Commit f8775e2

Browse files
committed
Adding persist prop to Control. Fixes #594
1 parent de0b3ed commit f8775e2

File tree

4 files changed

+78
-6
lines changed

4 files changed

+78
-6
lines changed

docs/api/Control.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
- [`ignore`](#prop-ignore)
1717
- [`disabled`](#disabled)
1818
- [`getRef`](#prop-getRef)
19+
- [`persist`](#prop-persist)
1920

2021
## `<Control>`
2122

@@ -347,3 +348,18 @@ _(Function)_: Calls the callback provided to the `getRef` prop with the node ins
347348
getRef={(node) => this.attach(node)}
348349
/>
349350
```
351+
352+
<h2 id="prop-persist"></h2>
353+
## `persist={false}`
354+
_(Boolean)_: Signifies that the field state (validation, etc.) should not persist when the component is unmounted. Default: `false`
355+
356+
```jsx
357+
// If user.name is less than 8 characters and persist == true, its validity will be:
358+
// { length: false }
359+
// even when the control is unmounted.
360+
<Control.text
361+
model="user.name"
362+
validators={{ length: (value) => value.length > 8 }}
363+
persist
364+
/>
365+
```

react-redux-form.d.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,10 @@ export interface ControlProps<T> extends React.HTMLProps<T> {
206206
* to event handlers as the second prop.
207207
*/
208208
withField?: boolean;
209+
/**
210+
* Signifies that the field state (validation, etc.) should not persist when the component is unmounted. Default: false
211+
*/
212+
persist?: boolean;
209213
}
210214

211215
export class Control<T> extends React.Component<ControlProps<T>, {}> {
@@ -395,8 +399,8 @@ interface BaseFieldsetProps {
395399
className?: string;
396400
/**
397401
* The component that the <Fieldset> should be rendered to (default: "div").
398-
*
399-
* * For React Native, the View component is used to render the fieldset, if you import { Fieldset } from 'react-redux-form/native'.
402+
*
403+
* * For React Native, the View component is used to render the fieldset, if you import { Fieldset } from 'react-redux-form/native'.
400404
*/
401405
component?: React.ComponentClass<any> | string;
402406
}
@@ -405,7 +409,7 @@ export interface FieldsetProps extends BaseFieldsetProps {
405409
* The string or tracker representing the model value of the entire form in the store.
406410
*
407411
* You can also use partial models for <Control>, <Field>, and <Errors> components inside of <Fieldset> - they will be resolved to the fieldset's model.
408-
*
412+
*
409413
* In addition, you can use a partial model for <Fieldset> itself - it will resolve to the parent <Fieldset> (yes, you can nest fieldsets) or <Form> models.
410414
*/
411415
model: string | ModelGetterFn;

src/components/control-component.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ const propTypes = {
111111
getRef: PropTypes.func,
112112
withField: PropTypes.bool,
113113
debounce: PropTypes.number,
114+
persist: PropTypes.bool,
114115
};
115116

116117
const defaultStrategy = {
@@ -185,9 +186,10 @@ function createControlClass(customControlPropsMap = {}, s = defaultStrategy) {
185186
dispatch,
186187
validators = {},
187188
errors = {},
189+
persist,
188190
} = this.props;
189191

190-
if (fieldValue && !fieldValue.valid) {
192+
if (!persist && fieldValue && !fieldValue.valid) {
191193
const keys = Object.keys(validators)
192194
.concat(Object.keys(errors), this.willValidate ? validityKeys : []);
193195

@@ -595,7 +597,6 @@ function createControlClass(customControlPropsMap = {}, s = defaultStrategy) {
595597
control,
596598
getRef,
597599
} = this.props;
598-
// console.log('RENDERING', this.props.model);
599600

600601
const mappedProps = omit(this.getMappedProps(), disallowedProps);
601602

@@ -635,6 +636,7 @@ function createControlClass(customControlPropsMap = {}, s = defaultStrategy) {
635636
mapProps: controlPropsMap.default,
636637
component: 'input',
637638
withField: true,
639+
persist: false,
638640
};
639641

640642
function mapStateToProps(state, props) {

test/control-component-spec.js

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* eslint react/no-multi-comp:0 react/jsx-no-bind:0 */
1+
/* eslint react/no-multi-comp:0 react/jsx-no-bind:0 */
22
import { assert } from 'chai';
33
import React from 'react';
44
import ReactDOM from 'react-dom';
@@ -1950,5 +1950,55 @@ Object.keys(testContexts).forEach((testKey) => {
19501950
assert.equal(input.value, 'debounced');
19511951
});
19521952
});
1953+
1954+
describe('persist prop', () => {
1955+
const initialState = getInitialState({ foo: 'bar' });
1956+
const store = testCreateStore({
1957+
test: modelReducer('test', initialState),
1958+
testForm: formReducer('test', initialState),
1959+
});
1960+
1961+
it('should persist validation on unmount when persist = true', () => {
1962+
const container = document.createElement('div');
1963+
1964+
const field = ReactDOM.render(
1965+
<Provider store={store}>
1966+
<Control.input
1967+
model="test.foo"
1968+
validators={{ valid: () => false }}
1969+
persist
1970+
/>
1971+
</Provider>,
1972+
container);
1973+
1974+
const input = TestUtils.findRenderedDOMComponentWithTag(field, 'input');
1975+
1976+
ReactDOM.unmountComponentAtNode(container);
1977+
1978+
assert.isFalse(store.getState().testForm.foo.valid);
1979+
assert.deepEqual(store.getState().testForm.foo.validity, { valid: false });
1980+
});
1981+
1982+
it('should not persist validation on unmount when persist = false (default)', () => {
1983+
const container = document.createElement('div');
1984+
1985+
const field = ReactDOM.render(
1986+
<Provider store={store}>
1987+
<Control.input
1988+
model="test.foo"
1989+
validators={{ valid: () => false }}
1990+
persist={false}
1991+
/>
1992+
</Provider>,
1993+
container);
1994+
1995+
const input = TestUtils.findRenderedDOMComponentWithTag(field, 'input');
1996+
1997+
ReactDOM.unmountComponentAtNode(container);
1998+
1999+
assert.isTrue(store.getState().testForm.foo.valid);
2000+
assert.deepEqual(store.getState().testForm.foo.validity, {});
2001+
});
2002+
});
19532003
});
19542004
});

0 commit comments

Comments
 (0)