forked from redux-form/redux-form
-
Notifications
You must be signed in to change notification settings - Fork 0
/
createField.js
158 lines (137 loc) · 4.31 KB
/
createField.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// @flow
import React, { Component, createElement } from 'react'
import PropTypes from 'prop-types'
import invariant from 'invariant'
import createConnectedField from './ConnectedField'
import shallowCompare from './util/shallowCompare'
import prefixName from './util/prefixName'
import plain from './structure/plain'
import type {
ConnectedComponent,
Structure,
ReactContext
} from './types.js.flow'
import type { InstanceApi as ConnectedFieldInstanceApi } from './ConnectedField.types'
import type { Props } from './FieldProps.types'
const createField = (structure: Structure<*, *>) => {
const ConnectedField = createConnectedField(structure)
const { setIn } = structure
class Field extends Component<Props> {
context: ReactContext
ref: ?ConnectedComponent<ConnectedFieldInstanceApi>
constructor(props: Props, context: ReactContext) {
super(props, context)
if (!context._reduxForm) {
throw new Error(
'Field must be inside a component decorated with reduxForm()'
)
}
}
shouldComponentUpdate(nextProps: Props, nextState?: Object) {
return shallowCompare(this, nextProps, nextState)
}
componentWillMount() {
this.context._reduxForm.register(
this.name,
'Field',
() => this.props.validate,
() => this.props.warn
)
}
componentWillReceiveProps(nextProps: Props, nextContext: any) {
const oldName = prefixName(this.context, this.props.name)
const newName = prefixName(nextContext, nextProps.name)
if (
oldName !== newName ||
// use deepEqual here because they could be a function or an array of functions
!plain.deepEqual(this.props.validate, nextProps.validate) ||
!plain.deepEqual(this.props.warn, nextProps.warn)
) {
// unregister old name
this.context._reduxForm.unregister(oldName)
// register new name
this.context._reduxForm.register(
newName,
'Field',
() => nextProps.validate,
() => nextProps.warn
)
}
}
componentWillUnmount() {
this.context._reduxForm.unregister(this.name)
}
saveRef = (ref: ?ConnectedComponent<ConnectedFieldInstanceApi>) =>
(this.ref = ref)
getRenderedComponent(): ?React.Component<*, *> {
invariant(
this.props.withRef,
'If you want to access getRenderedComponent(), ' +
'you must specify a withRef prop to Field'
)
return this.ref
? this.ref.getWrappedInstance().getRenderedComponent()
: undefined
}
get name(): string {
return prefixName(this.context, this.props.name)
}
get dirty(): boolean {
return !this.pristine
}
get pristine(): boolean {
return !!(this.ref && this.ref.getWrappedInstance().isPristine())
}
get value(): any {
return this.ref && this.ref.getWrappedInstance().getValue()
}
normalize = (name: string, value: any): any => {
const { normalize } = this.props
if (!normalize) {
return value
}
const previousValues = this.context._reduxForm.getValues()
const previousValue = this.value
const nextValues = setIn(previousValues, name, value)
return normalize(value, previousValue, nextValues, previousValues)
}
render() {
return createElement(ConnectedField, {
...this.props,
name: this.name,
normalize: this.normalize,
_reduxForm: this.context._reduxForm,
ref: this.saveRef
})
}
}
Field.propTypes = {
name: PropTypes.string.isRequired,
component: PropTypes.oneOfType([PropTypes.func, PropTypes.string])
.isRequired,
format: PropTypes.func,
normalize: PropTypes.func,
onBlur: PropTypes.func,
onChange: PropTypes.func,
onFocus: PropTypes.func,
onDragStart: PropTypes.func,
onDrop: PropTypes.func,
parse: PropTypes.func,
props: PropTypes.object,
validate: PropTypes.oneOfType([
PropTypes.func,
PropTypes.arrayOf(PropTypes.func)
]),
warn: PropTypes.oneOfType([
PropTypes.func,
PropTypes.arrayOf(PropTypes.func)
]),
withRef: PropTypes.bool,
immutableProps: PropTypes.arrayOf(PropTypes.string)
}
Field.contextTypes = {
_reduxForm: PropTypes.object
}
return Field
}
export default createField