Refactoring from classes to functions – ways to enhance in functions

Tags: , , ,



I am trying to rewrite class components to functions.

Often, I have an enhanced component as class property:

class Grid extends Component {

  tableCell = params => (
     <TableCell paging={this.props.paging} {...params} />
  )

  render() {
    return <Table tableCell={this.tableCell} />
  }
}

When writing function, I have to move the enhancing outside of function body, or it will get re-mounted on each render.

const tableCell = params => <TableCell {...params} />

function Grid(props) {
  return <Table tableCell={tableCell} />
}

Table is an external Component (devexpressGrid), but I suppose it does something like this:

function Table(props) {
  const TableCell = props.tableCell
  return <TableCell param1={true} param2={true} />
}

Is there a way, to still pass a prop from Grid to tableCell? This prop is not coming from any redux store, it is given when rendering Grid, like this:

return <Grid paging="infinite-scroll" />

You can see the differences here:

https://codesandbox.io/s/w2y76w53ww?fontsize=14

Answer

The problem is that Table treats tableCell function as a component. If there’s new function, the hierarchy is remounted. And new function is supposed to be created in order to use props from Grid, it cannot work the same way as it does in class component because there’s no this.prop that could be accessed as a property during component lifespan.

This is a common problem. React Router solves it by having separate component and render props. Accidentally providing newly created function as component will result in very same problem, a component will be remounted on each render.

tableCell should be treated as regular function rather than a component. As another answer mentions, tableCell is called render prop.

Table component should be:

function Table(props) {
  return props.tableCell({param1: true, param2: true});
}

Accidentally providing a component as render prop may result in error. It’s a good practice to follow naming convention and call a prop the way its purpose is clear, e.g. renderCell for render prop and Cell or cellComponent for a component.



Source: stackoverflow