Skip to content

Commit 95a4c58

Browse files
authored
Added documentation for parse/format & killed normalize (#76)
1 parent 99b60c8 commit 95a4c58

File tree

6 files changed

+26
-93
lines changed

6 files changed

+26
-93
lines changed

README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,10 @@ const MyForm = () => (
135135
* [`allowNull?: boolean`](#allownull-boolean)
136136
* [`children?: ((props: FieldRenderProps) => React.Node) | React.Node`](#children-props-fieldrenderprops--reactnode--reactnode)
137137
* [`component?: React.ComponentType<FieldRenderProps>`](#component-reactcomponenttypefieldrenderprops)
138+
* [`format?: ((value: any, name: string) => any) | null`](#format-value-any-name-string--any--null)
138139
* [`isEqual?: (a: any, b: any) => boolean`](#isequal-a-any-b-any--boolean)
139140
* [`name: string`](#name-string)
141+
* [`parse?: ((value: any, name: string) => any) | null`](#parse-value-any-name-string--any--null)
140142
* [`render?: (props: FieldRenderProps) => React.Node`](#render-props-fieldrenderprops--reactnode)
141143
* [`subscription?: FieldSubscription`](#subscription-fieldsubscription)
142144
* [`validate?: (value: ?any, allValues: Object) => ?any`](#validate-value-any-allvalues-object--any)
@@ -168,7 +170,7 @@ const MyForm = () => (
168170
* [`decorators?: Decorator[]`](#decorators-decorator)
169171
* [`initialValues?: Object`](#initialvalues-object)
170172
* [`mutators?: { [string]: Mutator }`](#mutators--string-mutator-)
171-
* [`onSubmit: (values: Object, callback: ?(errors: ?Object) => void) => ?Object | Promise<?Object> | void`](#onsubmit-values-object-callback-errors-object--void--object--promiseobject--void)
173+
* [`onSubmit: (values: Object, form: FormApi, callback: ?(errors: ?Object) => void) => ?Object | Promise<?Object> | void`](#onsubmit-values-object-form-formapi-callback-errors-object--void--object--promiseobject--void)
172174
* [`render?: (props: FormRenderProps) => React.Node`](#render-props-formrenderprops--reactnode)
173175
* [`subscription?: FormSubscription`](#subscription-formsubscription)
174176
* [`validate?: (values: Object) => Object | Promise<Object>`](#validate-values-object--object--promiseobject)
@@ -345,6 +347,12 @@ as any non-API props passed into the `<Field/>` component.
345347
A component that is given [`FieldRenderProps`](#fieldrenderprops) as props, as
346348
well as any non-API props passed into the `<Field/>` component.
347349

350+
#### `format?: ((value: any, name: string) => any) | null`
351+
352+
A function that takes the value from the form values and the name of the field and formats the value to give to the input. Common use cases include converting javascript `Date` values into a localized date string. Almost always used in conjunction with `parse`.
353+
354+
**Note: If you pass `null` to `format`, it will override the default behavior of converting `undefined` into `''`. If you do this, making sure your inputs are "controlled" is up to you.**
355+
348356
#### `isEqual?: (a: any, b: any) => boolean`
349357

350358
[See the 🏁 Final Form docs on `isEqual`](https://github.com/final-form/final-form#isequal-a-any-b-any--boolean).
@@ -353,6 +361,12 @@ well as any non-API props passed into the `<Field/>` component.
353361

354362
The name of your field.
355363

364+
#### `parse?: ((value: any, name: string) => any) | null`
365+
366+
A function that takes the value from the input and name of the field and converts the value into the value you want stored as this field's value in the form. Common usecases include converting strings into `Number`s or parsing localized dates into actual javascript `Date` objects. Almost always used in conjuction with `format`.
367+
368+
**Note: If you pass `null` to `parse`, it will override the default behavior of converting `''` into `undefined`, thus allowing you to have form values of `''`.**
369+
356370
#### `render?: (props: FieldRenderProps) => React.Node`
357371

358372
A render function that is given [`FieldRenderProps`](#fieldrenderprops), as well

src/Field.js

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,7 @@ export default class Field extends React.PureComponent<Props, State> {
3131

3232
static defaultProps = {
3333
format: (value: ?any, name: string) => (value === undefined ? '' : value),
34-
parse: (value: ?any, name: string) => (value === '' ? undefined : value),
35-
normalize: (value: ?any, previousValue: ?any, allValues: Object) => value
34+
parse: (value: ?any, name: string) => (value === '' ? undefined : value)
3635
}
3736

3837
constructor(props: Props, context: ReactContext) {
@@ -76,17 +75,6 @@ export default class Field extends React.PureComponent<Props, State> {
7675

7776
notify = (state: FieldState) => this.setState({ state })
7877

79-
parseAndNormalize = (value: ?any) => {
80-
if (this.props.parse !== null) {
81-
value = this.props.parse(value, this.props.name)
82-
}
83-
return this.props.normalize(
84-
value,
85-
this.state.state.value,
86-
this.context.reactFinalForm.getState().values
87-
)
88-
}
89-
9078
componentWillReceiveProps(nextProps: Props) {
9179
const { name, subscription } = nextProps
9280
if (
@@ -114,9 +102,12 @@ export default class Field extends React.PureComponent<Props, State> {
114102
this.state.state.blur()
115103
},
116104
onChange: (event: SyntheticInputEvent<*> | any) => {
105+
const { parse } = this.props
117106
const value: any =
118107
event && event.target ? getValue(event, isReactNative) : event
119-
this.state.state.change(this.parseAndNormalize(value))
108+
this.state.state.change(
109+
parse !== null ? parse(value, this.props.name) : value
110+
)
120111
},
121112
onFocus: (event: ?SyntheticFocusEvent<*>) => {
122113
this.state.state.focus()
@@ -130,7 +121,6 @@ export default class Field extends React.PureComponent<Props, State> {
130121
children,
131122
format,
132123
parse,
133-
normalize,
134124
isEqual,
135125
name,
136126
subscription,

src/Field.test.js

Lines changed: 1 addition & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -193,74 +193,6 @@ describe('Field', () => {
193193
expect(render.mock.calls[2][0].values.foo).toBeUndefined()
194194
})
195195

196-
it('should accept parse and normalize function props', () => {
197-
const parse = jest.fn((value, name) => `parse.${value}`)
198-
const normalize = jest.fn(
199-
(value, previousValue, allValues) => `normalize.${value}`
200-
)
201-
const renderInput = jest.fn(({ input }) => <input {...input} />)
202-
const render = jest.fn(() => (
203-
<form>
204-
<Field
205-
name="foo"
206-
render={renderInput}
207-
parse={parse}
208-
normalize={normalize}
209-
/>
210-
<Field name="boo" component="select" />
211-
</form>
212-
))
213-
214-
const dom = TestUtils.renderIntoDocument(
215-
<Form
216-
onSubmit={onSubmitMock}
217-
render={render}
218-
initialValues={{ boo: 'abc' }}
219-
/>
220-
)
221-
222-
expect(render).toHaveBeenCalled()
223-
expect(render).toHaveBeenCalledTimes(1)
224-
expect(render.mock.calls[0][0].values).toEqual({
225-
foo: undefined,
226-
boo: 'abc'
227-
})
228-
229-
const input = TestUtils.findRenderedDOMComponentWithTag(dom, 'input')
230-
231-
TestUtils.Simulate.change(input, { target: { value: 'bar' } })
232-
233-
expect(render).toHaveBeenCalledTimes(2)
234-
expect(render.mock.calls[1][0].values.foo).toBe('normalize.parse.bar')
235-
236-
expect(parse).toHaveBeenCalled()
237-
expect(parse).toHaveBeenCalledTimes(1)
238-
expect(parse.mock.calls[0]).toEqual(['bar', 'foo'])
239-
240-
expect(normalize).toHaveBeenCalled()
241-
expect(normalize).toHaveBeenCalledTimes(1)
242-
expect(normalize.mock.calls[0]).toEqual([
243-
'parse.bar',
244-
undefined,
245-
{ foo: undefined, boo: 'abc' }
246-
])
247-
248-
TestUtils.Simulate.change(input, { target: { value: 'x' } })
249-
250-
expect(render).toHaveBeenCalledTimes(3)
251-
expect(render.mock.calls[2][0].values.foo).toBe('normalize.parse.x')
252-
253-
expect(parse).toHaveBeenCalledTimes(2)
254-
expect(parse.mock.calls[1]).toEqual(['x', 'foo'])
255-
256-
expect(normalize).toHaveBeenCalledTimes(2)
257-
expect(normalize.mock.calls[1]).toEqual([
258-
'parse.x',
259-
'normalize.parse.bar',
260-
{ foo: 'normalize.parse.bar', boo: 'abc' }
261-
])
262-
})
263-
264196
it('should accept a null parse prop to preserve empty strings', () => {
265197
const renderInput = jest.fn(({ input }) => <input {...input} />)
266198
const render = jest.fn(() => (
@@ -369,7 +301,7 @@ describe('Field', () => {
369301
expect(select.value).toBe('')
370302
})
371303

372-
it("should convert null values to ''", () => {
304+
it("should convert undefined values to ''", () => {
373305
const renderInput = jest.fn(({ input }) => (
374306
<input {...input} value={input.value} />
375307
))

src/ReactFinalForm.test.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,11 +175,10 @@ describe('ReactFinalForm', () => {
175175

176176
const form = TestUtils.findRenderedDOMComponentWithTag(dom, 'form')
177177
TestUtils.Simulate.submit(form)
178-
const formComponent = TestUtils.findRenderedComponentWithType(dom, Form)
179178

180179
expect(onSubmit).toHaveBeenCalled()
181180
expect(onSubmit).toHaveBeenCalledTimes(1)
182-
expect(onSubmit).toHaveBeenCalledWith({ foo: 'bar' }, formComponent.form)
181+
expect(onSubmit.mock.calls[0][0]).toEqual({ foo: 'bar' })
183182
})
184183

185184
it('should reinitialize when initialValues prop changes', () => {

src/index.d.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,9 @@ export type FormProps = {
6262

6363
export type FieldProps = {
6464
allowNull?: boolean
65-
format: (value: any, name: string) => any | null
66-
parse: (value: any, name: string) => any | null
65+
format: ((value: any, name: string) => any) | null
66+
parse: ((value: any, name: string) => any) | null
6767
name: string
68-
normalize: (value: any, previousValue: any, allValues: object) => any
6968
subscription?: FieldSubscription
7069
validate?: (value: any, allValues: object) => any
7170
value?: any

src/types.js.flow

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,10 @@ export type FormProps = {
6363

6464
export type FieldProps = {
6565
allowNull?: boolean,
66-
format: (value: ?any, name: string) => ?any | null,
67-
parse: (value: ?any, name: string) => ?any | null,
66+
format: ((value: any, name: string) => any) | null,
6867
isEqual?: (a: any, b: any) => boolean,
6968
name: string,
70-
normalize: (value: ?any, previousValue: ?any, allValues: Object) => ?any,
69+
parse: ((value: any, name: string) => any) | null,
7170
subscription?: FieldSubscription,
7271
validate?: (value: ?any, allValues: Object) => ?any,
7372
validateFields?: string[],

0 commit comments

Comments
 (0)