Является ли определение функционального компонента внутри функции render () анти-шаблоном?

Я хочу знать, является ли это антипаттерном или каким-то образом влияет на компонент, чтобы сделать что-то вроде этого:

render() {
  const MyFuncComponent = ({ prop1, prop2 }) => (
    // code here
  )

  return (
    <div>
      <MyFuncComponent prop1 = {something} prop2 = {else} />
    </div>
  )
}

Я так считаю. Обычно в функции рендеринга вы помещаете только некоторые вычисляемые переменные, чтобы уменьшить код в вашем JSX.

Phiter 17.09.2018 18:23

Я не думаю, что мы должны это делать. Таким образом, каждый раз, когда состояние обновляется, функция переопределяется.

Arpit Kapadia 17.09.2018 18:25

@ArpitKapadia да, в этом есть смысл, спасибо!

corasan 17.09.2018 18:35

… И я уверен, что React не заметит, что это все тот же компонент.

Bergi 17.09.2018 18:43
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
5
4
1 599
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

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

Для конкретного примера, который вы привели, я бы рекомендовал не определять другой компонент реакции в рендере. Если вы все же определяете какие-либо функции в рендере, они должны быть связаны с тем, что делает рендер. Определение другого компонента или добавление кучи функций внутри рендера может сделать его громоздким и трудным для понимания того, что делает код.

Да, это антипаттерн по той же причине, что мы не должны использовать компонент высшего порядка внутри render.

Don’t Use HOCs Inside the render Method

React’s diffing algorithm (called reconciliation) uses component identity to determine whether it should update the existing subtree or throw it away and mount a new one. If the component returned from render is identical (===) to the component from the previous render, React recursively updates the subtree by diffing it with the new one. If they’re not equal, the previous subtree is unmounted completely.

Normally, you shouldn’t need to think about this. But it matters for HOCs because it means you can’t apply a HOC to a component within the render method of a component:

render() {
  // A new version of EnhancedComponent is created on every render
  // EnhancedComponent1 !== EnhancedComponent2
  const EnhancedComponent = enhance(MyComponent);
  // That causes the entire subtree to unmount/remount each time!
  return <EnhancedComponent />;
}

The problem here isn’t just about performance — remounting a component causes the state of that component and all of its children to be lost.

Это означает, что новый компонент появится в дереве React (которое можно изучить с помощью реагировать-devtools), но он не сохранит никакого состояния, а методы жизненного цикла, такие как componentDidMount, componentWillUnmount, useEffect, всегда будут вызываться в каждом цикле рендеринга.

Решения

Поскольку, вероятно, есть причины для динамического создания компонента, вот несколько общих шаблонов, позволяющих избежать ловушек.

Определите новый компонент снаружи

Либо в собственном файле, либо непосредственно над определением родительского компонента. Передайте любую переменную в качестве свойств вместо использования родительской области компонента для доступа к значениям.

const MyFuncComponent = ({ prop1, prop2 }) => <>{/* code here */}</>;

const MyComponent = props => (
  <div>
    {props.list.map(({ something, thing }) => (
      <MyFuncComponent prop1 = {something} prop2 = {thing} />
    ))}
  </div>
);

Вспомогательная функция

Обычная функция, возвращающая JSX, может быть определенный и использовал непосредственно внутри другого компонента. Он не будет отображаться как новый компонент в дереве React, будет отображаться только его результат, как если бы он был встроен.

Таким образом, мы также можем использовать переменные из окружающей области (например, props.itemClass в следующем примере) в дополнение к любым другим параметрам, которые вы хотите.

const MyComponent = props => {
  // Looks like a component, but only serves as a function.
  const renderItem = ({ prop1, prop2 }) => (
    <li className = {props.itemClass}> {/* <-- param from enclosing scope */}
      {prop1} {prop2} {/* other code */}
    </li>
  );

  return <ul>{props.list.map(renderItem)}</ul>;
};

Его также можно определить вне компонента, поскольку он действительно гибкий.

const renderItem = (itemClass, { prop1, prop2 }) => (
  <li className = {itemClass}>
    {prop1} {prop2} {/* other code */}
  </li>
);

const MyComponent = props => (
  <ul>
    {props.list.map(item => renderItem(props.itemClass, item))}
  </ul>
);

Но на этом этапе мы должны просто определить компонент React, а не подделывать его с помощью функции. Используйте React предсказуемо и в полной мере.

Встроить логику

Очень часто встраивать JSX внутри условия или обратного вызова map.

const MyComponent = ({ itemClass }) => (
  <ul>
    {props.list.map(({ something, thing }) => (
      <li className = {itemClass}>
        {something} {thing} {/* other code */}
      </li>
    ))}
  </ul>
);

Если мы обнаружим, что копируем тот же встроенный JSX повсюду, возможно, пришло время заключить его в его собственный повторно используемый компонент.

Другие вопросы по теме