Рефакторинг от классов к функциям - способы улучшения функций - PullRequest
0 голосов
/ 11 апреля 2019

Я пытаюсь переписать компоненты класса в функции.

Часто у меня есть расширенный компонент как свойство класса:

class Grid extends Component {

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

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

При написании функции я должен перемещать расширение вне тела функции, иначе оно будет перемонтировано при каждом рендере.

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

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

Таблица - это внешний компонент (devexpressGrid), но я предполагаю, что он делает что-то вроде этого:

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

Есть ли способ по-прежнему передавать реквизит из Grid в tableCell? Этот реквизит не исходит из какого-либо редукционного магазина, он дается при рендеринге Grid, например:

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

Вы можете увидеть различия здесь:

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

Ответы [ 3 ]

1 голос
/ 11 апреля 2019

Вы можете использовать шаблон renderProps здесь (я думаю, что все еще можно использовать его, но вы, вероятно, могли бы быть еще круче и посмотреть на его замену на крючки)

function Table(props) {
  return (
    <div>
     {props.render(props)}
    </div>
  )
}

Реализация:

function Grid(props) {
  return (
    <Table render={(props) => <TableCell {...props} />} />
  )
}

Таким образом, ваша таблица может визуализировать любой компонент и передать ему все необходимые реквизиты. ИМХО это делает таблицу очень гибкой.

1 голос
/ 11 апреля 2019

Вы можете создать новую встроенную функцию и передать ее непосредственно tableCell prop.

function Grid(props) {
  return (
    <Table tableCell={params => <TableCell paging={paging} {...params} />} />
  )
}

Если вы не хотите создавать новую функцию при каждом рендеринге, вы можете использовать useCallback крючок.

function Grid(props) {
  const tableCell = useCallback(
    params => <TableCell paging={paging} {...params} />,
    [paging]
  );

  return <Table tableCell={tableCell} />;
}
0 голосов
/ 11 апреля 2019

Проблема в том, что Table рассматривает функцию tableCell как компонент. Если есть новая функция, иерархия перемонтируется. И новая функция должна быть создана для использования props из Grid, она не может работать так же, как в компоненте класса, потому что нет this.prop, к которому можно было бы получить доступ как свойство в течение срока службы компонента.

Это распространенная проблема. React Router решает проблему с помощью отдельных component и render реквизитов . Случайное предоставление новой созданной функции как component приведет к той же самой проблеме, компонент будет перемонтироваться при каждом рендеринге.

tableCell следует рассматривать как обычную функцию, а не как компонент. В другом ответе упоминается, что tableCell называется render prop .

Table компонент должен быть:

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

Случайное предоставление компонента в качестве опоры рендеринга может привести к ошибке. Хорошей практикой является следовать соглашению об именах и называть опору так, как понятно ее назначение, например, renderCell для рендера и Cell или cellComponent для компонента.

...