1

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.

1 Answer 1

5

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));
Sign up to request clarification or add additional context in comments.

3 Comments

My action deleteExperince, you don't use it anywhere, so when I click on delete nothing happens :).
@dragon I use it here: const del = useCallback(() => deleteExperience(exp._id), [exp._id]);
@dragon Wait a minute. You have two things both named deleteExperience, one that you import and another that's a prop? Answer edited to use the other one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.