Reputation: 1274
I follow a React/Redux tutorial and from what I saw on a few articles on internet I realized that inline functions are bad for performance in React.
From what I understood functions are reference type and if you use an inline function, for every re-render, this function will take a different spot in memory.
In the tutorial example I have this deleteExperience() method, that the instructor used inline.
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import Moment from 'react-moment';
import { Link, withRouter } from 'react-router-dom';
import { deleteExperience } from '../../actions/profileActions';
const Experience = ({ experience, deleteExperience }) => {
const experiences = experience.map(exp => (
<tr key={exp._id}>
<td>{exp.company}</td>
<td className="hide-sm">{exp.title}</td>
<td>
<Moment format="YYYY/MM/DD">{exp.from}</Moment> -
{exp.to === null ? (
' Now '
) : (
<Moment format="YYYY/MM/DD">{exp.to}</Moment>
)}
</td>
<td>
<button className="btn btn-danger" onClick={() => deleteExperience(exp._id)}>
Delete
</button>
</td>
</tr>
));
return (
<Fragment>
<h2 className="my-2">Experience Credentials</h2>
<table className="table">
<thead>
<tr>
<th>Company</th>
<th className="hide-sm">Title</th>
<th className="hide-sm">Years</th>
<th />
</tr>
</thead>
<tbody>{experiences}</tbody>
</table>
</Fragment>
);
};
Experience.propTypes = {
experience: PropTypes.array.isRequired,
deleteExperience: PropTypes.func
};
export default connect(
null,
{deleteExperience}
)(withRouter(Experience));
So the instructor said that he used inline function
onClick={() => deleteExperience(exp._id)}
and not just called directly the function
onClick={deleteExperience(exp._id)}
to not be execute immediately.
So, please someone tell me, if the theory about bad practice to use inline function is true, how to handle this situation? I tried many ways, without any success.
Upvotes: 1
Views: 546
Reputation: 48672
The performance issue isn't from using arrow functions, but rather from creating fresh ones on every render. In your case, you can use useCallback()
to memoize them. (You'll need to extract a component to render each exp
object to avoid breaking the rules of hooks.) Something like this should work:
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import Moment from 'react-moment';
import { Link, withRouter } from 'react-router-dom';
import { deleteExperience } from '../../actions/profileActions';
const Exp = ({ exp, deleteExperience }) => {
const del = useCallback(() => deleteExperience(exp._id), [deleteExperience, exp._id]);
return (
<tr>
<td>{exp.company}</td>
<td className="hide-sm">{exp.title}</td>
<td>
<Moment format="YYYY/MM/DD">{exp.from}</Moment> -
{exp.to === null ? (
' Now '
) : (
<Moment format="YYYY/MM/DD">{exp.to}</Moment>
)}
</td>
<td>
<button className="btn btn-danger" onClick={del}>
Delete
</button>
</td>
</tr>
);
};
const Experience = ({ experience, deleteExperience }) => {
const experiences = experience.map(exp => (
<Exp key={exp._id} exp={exp} deleteExperience={deleteExperience} />
));
return (
<Fragment>
<h2 className="my-2">Experience Credentials</h2>
<table className="table">
<thead>
<tr>
<th>Company</th>
<th className="hide-sm">Title</th>
<th className="hide-sm">Years</th>
<th />
</tr>
</thead>
<tbody>{experiences}</tbody>
</table>
</Fragment>
);
};
Experience.propTypes = {
experience: PropTypes.array.isRequired,
deleteExperience: PropTypes.func
};
export default connect(
null,
{deleteExperience}
)(withRouter(Experience));
Upvotes: 5