Вопрос по transclusion, javascript, composition, reactjs, template-engine – React.js: перенос одного компонента в другой

154

Многие языки шаблонов имеютслоты» или же "Уступать" операторы, которые позволяют сделать какое-то обращение контроля, чтобы обернуть один шаблон в другой.

Угловой имеетtransclude» вариант.

Rails имеетзаявление о доходности, Если бы в React.js был оператор yield, он бы выглядел так:

var Wrapper = React.createClass({
  render: function() {
    return (
      
        before
          
        after
      
    );
  }
});

var Main = React.createClass({
  render: function() {
    return (
      content
    );
  }
});

Желаемый вывод:


  before
    content
  after

Увы, React.js не делаетне иметь, Как определить компонент Wrapper для достижения того же результата?

Ваш Ответ

3   ответа
208

Пытаться:

var Wrapper = React.createClass({
  render: function() {
    return (
      
        before
          {this.props.children}
        after
      
    );
  }
});

УвидетьНесколько компонентов: дети а такжеТип Детского реквизита в документах для получения дополнительной информации.

Или вы можете использовать компонент высшего порядка :)stackoverflow.com/a/31564812/82609 Sebastien Lorber
119
С помощьюchildren
const Wrapper = ({children}) => (
  
    header
    {children}
    footer
  
);

const App = ({name}) => Hello {name};

const WrappedApp = ({name}) => (
  
    
  
);

render(,node);

Это также известно какtransclusion в угловых.

children является специальной опорой в React и будет содержать то, что находится внутри вашего компонента »с тегами (здесь это внутриWrapperтак что этоchildren

Обратите внимание, что вы нет обязательно нужно использоватьchildren, который является уникальным для компонента, и вы можете использовать обычные реквизиты, если хотите, или смешивать реквизиты и потомки:

const AppLayout = ({header,footer,children}) => (
  
    {header}
    {children}
    {footer}
  
);

const appElement = (
  
    body
  
);

render(appElement,node);

Это просто и хорошо для многих случаев, и яЯ рекомендую это для большинства потребительских приложений.

сделать реквизит

Можно передать функции рендеринга компоненту, этот шаблон обычно называетсяrender propиchildren prop часто используется для обеспечения этого обратного вызова.

Этот шаблон не предназначен для макета. Компонент-обертка обычно используется для хранения и управления некоторым состоянием и добавления его в функции рендеринга.

Встречный пример:

const Counter = () => (
  
    {(val, set) => (
       set(val + 1)}>  
        clicked {val} times
      
    )}
  
); 

Вы можете получить еще больше фантазии и даже предоставить объект


  {{
    loading: () => ...,
    success: (data) => {data.something},
    error: (e) => {e.message},
  }}

Обратите внимание, что вы нет обязательно нужно использоватьchildrenЭто вопрос вкуса / API.

 ...}
  renderSuccess={(data) => {data.something}}
  renderError={(e) => {e.message}}
/>

На сегодняшний день многие библиотеки используют реквизит рендеринга (контекст React, React-motion, Apollo ...), потому что люди склонны находить этот API проще, чем HOC 's.реагируют-вилка электропитания это коллекция простых компонентов render-prop.реагируют-принять поможет вам сделать композицию.

Компоненты высшего порядка (HOC).
const wrapHOC = (WrappedComponent) => {
  class Wrapper extends React.PureComponent {
    render() {
      return (
        
          header
          
          footer
        
      );
    }  
  }
  return Wrapper;
}

const App = ({name}) => Hello {name};

const WrappedApp = wrapHOC(App);

render(,node);

Компонент высшего порядка / HOC обычно это функция, которая принимает компонент и возвращает новый компонент.

Использование компонента высшего порядка может быть более производительным, чем использованиеchildren или жеrender propsпотому что обертка может иметь возможность замкнуть рендеринг на шаг впереди.shouldComponentUpdate

Здесь мы используемPureComponent, При повторном рендеринге приложения, еслиWrappedApp Название реквизита не меняется со временем, обертка имеет возможность сказать:Я ненужно рендерить, потому что реквизиты (собственно имя) такие же, как и раньше ", Сchildren решение на основе выше, даже если оберткаPureComponent, это не так, потому что дочерний элемент воссоздается каждый раз при визуализации родительского элемента, что означает, что оболочка, скорее всего, всегда будет повторно визуализироваться, даже если обернутый компонент является чистым. Eстьплагин Babel что может помочь смягчить это и обеспечить постоянныйchildren элемент со временем.

Заключение

Компоненты высшего порядка могут дать вам лучшую производительность. Это'Это не так сложно, но поначалу это выглядит недружелюбно.

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

Redux сначала использовал оболочку времени выполнения и позже переключился на HOCconnect(options)(Comp) по соображениям производительности (по умолчанию оболочка чистая и используетсяshouldComponentUpdate). Это отличная иллюстрация того, что я хотел выделить в этом ответе.

Обратите внимание, что если у компонента есть API рендеринга-пропа, поверх него обычно легко создать HOC, поэтому, если вы являетесь автором lib, вы должны сначала написать API-интерфейс рендеринга и в конечном итоге предложить версию HOC. Это то, что делает Аполлон компонент рендеринга иgraphql HOC с его помощью.

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

Это'более идиоматично их сочинять (compose(hoc1,hoc2)(Comp)) по сравнению с рендерингом реквизитаЭто может дать мне лучшие результаты.я знаком с этим стилем программирования

Я неНе стесняйтесь использовать / создавать HOC версии моих любимых инструментов:

РЕАКТContext.Consumer компнеустановленные-хSubscribeс помощьюgraphql HOC Аполлона вместоQuery оказывать опору

На мой взгляд, иногда реквизит рендеринга делает код более читабельным, иногда менее ... Я стараюсь использовать наиболее прагматичное решение в соответствии с имеющимися у меня ограничениями. Иногда читаемость важнее исполнения, иногда нет. Выбирай мудро и не делайНеукоснительно следуйте тенденции 2018 года по конвертации всего в рендер-реквизит.

Этот подход также облегчает передачу подпрограммы дочернему компоненту (в данном случае Hello). Начиная с React 0.14. * И далее, единственный способ передать реквизиты дочерним компонентам - это использовать React.createClone, который может быть дорогим. Mukesh Soni
Вопрос: ответ упоминает "лучшая производительность " - что я не делаюне понимаю: лучше по сравнению с каким другим решением? Philipp
Когда вы используете PureComponent, вы небольше не нужно возвращать функцию. Просто удалите одну функцию переноса:js const wrapHOC = (WrappedComponent) => { class Wrapper extends React.PureComponent { render() { return ( header footer ); } return Wrapper; } ColorWin
спасибо @ColorWin, это была опечатка, я исправил это Sebastien Lorber
29

В дополнение к Софиs ответ, я также нашел применение при отправке дочерних типов компонентов, делая что-то вроде этого:

var ListView = React.createClass({
    render: function() {
        var items = this.props.data.map(function(item) {
            return this.props.delegate({data:item});
        }.bind(this));
        return {items};
    }
});

var ItemDelegate = React.createClass({
    render: function() {
        return {this.props.data}
    }
});

var Wrapper = React.createClass({    
    render: function() {
        return 
    }
});
Вы можете добавить любые реквизиты, которые вы хотите, к компоненту и назвать их как хотите, я использую this.props.delegate в строке 4, но с тем же успехом мог бы назвать его как-нибудь иначе. krs
Я нене видел никакой документации поdelegate, как ты нашел это? NVI

Похожие вопросы