forked from redux-form/redux-form
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcreateFields.js
129 lines (113 loc) · 3.62 KB
/
createFields.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
// @flow
import { Component, createElement } from 'react'
import { polyfill } from 'react-lifecycles-compat'
import PropTypes from 'prop-types'
import invariant from 'invariant'
import createConnectedFields from './ConnectedFields'
import shallowCompare from './util/shallowCompare'
import plain from './structure/plain'
import prefixName from './util/prefixName'
import type { Structure, ReactContext } from './types'
import type { Props } from './FieldsProps.types'
import validateComponentProp from './util/validateComponentProp'
const validateNameProp = prop => {
if (!prop) {
return new Error('No "names" prop was specified <Fields/>')
}
if (!Array.isArray(prop) && !prop._isFieldArray) {
return new Error(
'Invalid prop "names" supplied to <Fields/>. Must be either an array of strings or the fields array generated by FieldArray.'
)
}
}
const createFields = (structure: Structure<*, *>) => {
const ConnectedFields = createConnectedFields(structure)
class Fields extends Component<Props> {
constructor(props: Props, context: ReactContext) {
super((props: Props), (context: ReactContext))
if (!context._reduxForm) {
throw new Error(
'Fields must be inside a component decorated with reduxForm()'
)
}
const error = validateNameProp(props.names)
if (error) {
throw error
}
}
shouldComponentUpdate(nextProps: Props) {
return shallowCompare(this, nextProps)
}
componentDidMount() {
const { context } = this
const {
_reduxForm: { register }
} = context
this.names.forEach(name => register(name, 'Field'))
}
componentWillReceiveProps(nextProps: Props) {
if (!plain.deepEqual(this.props.names, nextProps.names)) {
const { context } = this
const { register, unregister } = context._reduxForm
// unregister old name
this.props.names.forEach(name => unregister(prefixName(context, name)))
// register new name
nextProps.names.forEach(name =>
register(prefixName(context, name), 'Field')
)
}
}
componentWillUnmount() {
const { context } = this
const { unregister } = context._reduxForm
this.props.names.forEach(name => unregister(prefixName(context, name)))
}
getRenderedComponent() {
invariant(
this.props.withRef,
'If you want to access getRenderedComponent(), ' +
'you must specify a withRef prop to Fields'
)
return this.refs.connected.getWrappedInstance().getRenderedComponent()
}
get names(): string[] {
const { context } = this
return this.props.names.map(name => prefixName(context, name))
}
get dirty(): boolean {
return this.refs.connected.getWrappedInstance().isDirty()
}
get pristine(): boolean {
return !this.dirty
}
get values(): Object {
return (
this.refs.connected &&
this.refs.connected.getWrappedInstance().getValues()
)
}
render() {
const { context } = this
return createElement(ConnectedFields, {
...this.props,
names: this.props.names.map(name => prefixName(context, name)),
_reduxForm: this.context._reduxForm,
ref: 'connected'
})
}
}
Fields.propTypes = {
names: (props, propName) => validateNameProp(props[propName]),
component: validateComponentProp,
format: PropTypes.func,
parse: PropTypes.func,
props: PropTypes.object,
withRef: PropTypes.bool
}
Fields.contextTypes = {
_reduxForm: PropTypes.object
}
polyfill(Fields)
return Fields
}
export default createFields