Skip to content

Commit

Permalink
Fixed FieldArray rerender bug (#1590)
Browse files Browse the repository at this point in the history
  • Loading branch information
erikras committed Aug 23, 2016
1 parent c8857d5 commit b4fc32d
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 2 deletions.
13 changes: 11 additions & 2 deletions src/ConnectedFieldArray.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import { Component, PropTypes, createElement } from 'react'
import { connect } from 'react-redux'
import createFieldArrayProps from './createFieldArrayProps'
import { mapValues } from 'lodash'
import shallowCompare from './util/shallowCompare'
import plain from './structure/plain'

const propsToNotUpdateFor = [
'value'
]

const createConnectedFieldArray = ({
arrayInsert,
arrayMove,
Expand Down Expand Up @@ -35,7 +38,13 @@ const createConnectedFieldArray = ({

class ConnectedFieldArray extends Component {
shouldComponentUpdate(nextProps) {
return shallowCompare(this, nextProps)
return Object.keys(nextProps).some(prop => {
// useful to debug rerenders
// if (!plain.deepEqual(this.props[ prop ], nextProps[ prop ])) {
// console.info(prop, 'changed', this.props[ prop ], '==>', nextProps[ prop ])
// }
return !~propsToNotUpdateFor.indexOf(prop) && !deepEqual(this.props[ prop ], nextProps[ prop ])
})
}

get dirty() {
Expand Down
46 changes: 46 additions & 0 deletions src/__tests__/FieldArray.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,52 @@ const describeFieldArray = (name, structure, combineReducers, expect) => {
.toExist()
.toBe('No dogs')
})

it('should NOT rerender when a value changes', () => {
const store = makeStore({
testForm: {
values: {
dogs: [ 'Fido', 'Snoopy' ]
}
}
})
const renderField = createSpy(props => <input {...props.input}/>).andCallThrough()
const renderFieldArray =
createSpy(({ fields }) => (<div>
{fields.map(field => <Field name={field} component={renderField} key={field}/>)}
</div>)).andCallThrough()
class Form extends Component {
render() {
return <FieldArray name="dogs" component={renderFieldArray}/>
}
}
const TestForm = reduxForm({ form: 'testForm' })(Form)
TestUtils.renderIntoDocument(
<Provider store={store}>
<TestForm/>
</Provider>
)

// field array rendered
expect(renderFieldArray).toHaveBeenCalled()
expect(renderFieldArray.calls.length).toBe(1)

// both fields rendered
expect(renderField).toHaveBeenCalled()
expect(renderField.calls.length).toBe(2)
expect(renderField.calls[ 0 ].arguments[ 0 ].input.value).toBe('Fido')

// change first field
renderField.calls[ 0 ].arguments[ 0 ].input.onChange('Odie')

// first field rerendered, second field is NOT
expect(renderField.calls.length).toBe(3)
expect(renderField.calls[ 2 ].arguments[ 0 ].input.name).toBe('dogs[0]')
expect(renderField.calls[ 2 ].arguments[ 0 ].input.value).toBe('Odie')

// field array NOT rerendered
expect(renderFieldArray.calls.length).toBe(1)
})
})

it('should work with Fields', () => {
Expand Down

0 comments on commit b4fc32d

Please sign in to comment.