-
-
Save duyenho/8dc3a9c5b2cd3b4ea0234c63b6de647a to your computer and use it in GitHub Desktop.
performance - how to avoid bindings in react's render function
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// I have three forms. On each form, it is possible to add and remove form blocks. I created these util functions: | |
export function appendFormBlock(type) { | |
// New block ids created from the type, eg. 'dependant_1', 'authPerson_2', etc.. | |
const newBlock = `${type}_${this.state[`${type}FormBlocks`].length}`; | |
this.setState({ | |
[`${type}FormBlocks`]: this.state[`${type}FormBlocks`].concat([newBlock]), | |
}); | |
} | |
export function removeFormBlock(id) { | |
const type = id.split('_')[0]; | |
this.setState({ | |
[`${type}FormBlocks`]: this.state[`${type}FormBlocks`].filter(block => block !== id), | |
}); | |
} | |
export default class DoctorsPage extends React.Component { | |
constructor(props) { | |
super(props) | |
this.state = { doctorFormBlocks: ['doctor_0'] } | |
} | |
render() { | |
return ( | |
<div className="form__section"> | |
{doctorFormBlocks.map((block, i) => ( | |
<DoctorFormBlock | |
form={form} | |
key={block} | |
blockId={block} | |
index={i + 1} | |
handleRemove={removeFormBlock.bind(this, block)} | |
/> | |
))} | |
<AddRemoveButton | |
typeToAdd="doctor" | |
handleAppend={appendFormBlock.bind(this, 'doctor')} | |
/> | |
</div> | |
) | |
} | |
} | |
// I learned that binding functions in the render function is bad for performance - this is the main issue. | |
// Here is the form block: | |
export default class DoctorFormBlock extends React.Component { | |
static propTypes = { | |
form: PropTypes.object.isRequired, | |
index: PropTypes.number.isRequired, | |
blockId: PropTypes.string.isRequired, | |
handleRemove: PropTypes.func.isRequired, | |
}; | |
render() { | |
const {form, index, blockId, handleRemove} = this.props; | |
return ( | |
<section className="form__block" id={blockId}> | |
// Shows the remove button from the second instance of the form block onwards | |
{index > 1 && <AddRemoveButton isRemove handleRemove={handleRemove} />} | |
<h3>Doctor {index}</h3> | |
<LayoutField form={form} fieldId="doctorsSpeciality" sectionId="doctorDetailsForm" /> | |
<LayoutField form={form} fieldId="name" sectionId="doctorDetailsForm" /> | |
<LayoutField form={form} fieldId="address" sectionId="doctorDetailsForm" /> | |
<LayoutField form={form} fieldId="contactNumber" sectionId="doctorDetailsForm" /> | |
</section> | |
); | |
} | |
} | |
// And the add/remove button | |
export default class AddRemoveButton extends React.Component { | |
static propTypes = { | |
isRemove: PropTypes.bool, | |
typeToAdd: PropTypes.string, | |
handleAppend: PropTypes.func, | |
handleRemove: PropTypes.func, | |
}; | |
static defaultProps = { | |
isRemove: false, | |
typeToAdd: '', | |
handleAppend: () => {}, | |
handleRemove: () => {}, | |
}; | |
render() { | |
const {typeToAdd, isRemove, handleAppend, handleRemove} = this.props; | |
return ( | |
<div className="btn-holder"> | |
{typeToAdd && ( | |
<Button | |
key="btnAdd" | |
variant={Button.Variant.LINK} | |
className="add-btn" | |
onClick={handleAppend} | |
> | |
Add {typeToAdd} | |
</Button> | |
)} | |
{isRemove && ( | |
<Button | |
key="btnRemove" | |
variant={Button.Variant.LINK} | |
className="remove-btn" | |
onClick={handleRemove} | |
> | |
Remove | |
</Button> | |
)} | |
</div> | |
); | |
} | |
} | |
// I tried a few different approaches but it all felt over-complicated | |
// https://medium.freecodecamp.org/why-arrow-functions-and-bind-in-reacts-render-are-problematic-f1c08b060e36 | |
// https://medium.freecodecamp.org/react-pattern-extract-child-components-to-avoid-binding-e3ad8310725e | |
// 1. How would you go about avoiding these bindings? | |
// 2. Do you think the utils are overkill and I should write them long hand on each pages for better readability? |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment