Как передать компонент реакции в другой компонент реакции, чтобы включить содержимое первого компонента?

217

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

Редактировать: Вот кодекс ручки JJ, иллюстрирующий то, что я пытаюсь сделать. http://codepen.io/aallbrig/pen/bEhjo

HTML

<div id="my-component">
    <p>Hi!</p>
</div>

ReactJS

/**@jsx React.DOM*/

var BasicTransclusion = React.createClass({
  render: function() {
    // Below 'Added title' should be the child content of <p>Hi!</p>
    return (
      <div>
        <p> Added title </p>
        {this.props.children}
      </div>
    )
  }
});

React.renderComponent(BasicTransclusion(), document.getElementById('my-component'));
Эндрю Олбрайт
источник

Ответы:

198

Вы можете использовать this.props.childrenдля визуализации любых потомков, которые содержит компонент:

const Wrap = ({ children }) => <div>{children}</div>

export default () => <Wrap><h1>Hello word</h1></Wrap>
Дэвид Хеллсинг
источник
4
Я бы использовал этот ответ. this.props.childrenявляется частью API компонента и, как ожидается, будет использоваться таким образом. Примеры команды React используют эту технику, например, при передаче реквизита и при разговоре об одном ребенке .
Росс Аллен
Из моего комментария ниже: передавая его как реквизит, вы даже можете дать ему имя и использовать propTypes для проверки типа.
returneax
1
@AndrewAllbright: В вашем примере не было детей. Это работает: codepen.io/ssorallen/pen/Dyjmk
Росс Аллен
И на тот случай, если вы захотите получить DOM-узлы для детей: stackoverflow.com/questions/29568721/…
ericsoco
124

Обратите внимание, что я предоставил более подробный ответ здесь

Оболочка времени выполнения:

Это самый идиоматичный способ.

const Wrapper = ({children}) => (
  <div>
    <div>header</div>
    <div>{children}</div>
    <div>footer</div>
  </div>
);

const App = () => <div>Hello</div>;

const WrappedApp = () => (
  <Wrapper>
    <App/>
  </Wrapper>
);

Обратите внимание, что childrenэто «особая опора» в React, и приведенный выше пример является синтаксическим сахаром и (почти) эквивалентен<Wrapper children={<App/>}/>


Инициализация оболочки / HOC

Вы можете использовать Компонент высшего порядка (HOC). Они были добавлены в официальный документ недавно.

// Signature may look fancy but it's just 
// a function that takes a component and returns a new component
const wrapHOC = (WrappedComponent) => (props) => (
  <div>
    <div>header</div>
    <div><WrappedComponent {...props}/></div>
    <div>footer</div>
  </div>
)

const App = () => <div>Hello</div>;

const WrappedApp = wrapHOC(App);

Это может привести к (немного) лучшей производительности, потому что компонент-оболочка может закорочить рендеринг на один шаг вперед с shouldComponentUpdate, в то время как в случае оболочки-оболочки времени выполнения дочерний объект всегда будет отличаться от ReactElement и вызывать повторные рендеры. даже если ваши компоненты расширяют PureComponent.

Заметь connect Redux раньше был оболочкой времени выполнения, но был изменен на HOC, потому что он позволяет избежать бесполезных повторных рендеров, если вы используете эту pureопцию (которая по умолчанию верна)

Вы никогда не должны вызывать HOC на этапе рендеринга, потому что создание компонентов React может быть дорогостоящим. Вы должны скорее вызывать эти оболочки при инициализации.


Обратите внимание, что при использовании функциональных компонентов, подобных описанным выше, версия HOC не обеспечивает никакой полезной оптимизации, поскольку функциональные компоненты без сохранения состояния не реализуют shouldComponentUpdate

Больше объяснений здесь: https://stackoverflow.com/a/31564812/82609

Себастьян Лорбер
источник
29
const ParentComponent = (props) => {
  return(
    {props.childComponent}
    //...additional JSX...
  )
}

//import component
import MyComponent from //...where ever

//place in var
const myComponent = <MyComponent />

//pass as prop
<ParentComponent childComponent={myComponent} />
Джозеф Барнс
источник
Это было бы правильно, если бы это было ... React 15.x не позволяет вам возвращать многоузловой компонент. React 16 (он же React Fiber) позволит использовать несколько узлов. Вот исправление для вашего примера кода: const ParentComponent = (props) => ({props.childComponent}); импортировать MyComponent из //... везде когда-либо const myComponent = <MyComponent /> // передать как проп <ParentComponent childComponent = {myComponent} />
Эндрю Олбрайт
13

Facebook рекомендует использовать компонент без сохранения состояния. Источник: https://facebook.github.io/react/docs/reusable-components.html.

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

function Label(props){
    return <span>{props.label}</span>;
}

function Hello(props){
    return <div>{props.label}{props.name}</div>;
}

var hello = Hello({name:"Joe", label:Label({label:"I am "})});

ReactDOM.render(hello,mountNode);
Sud
источник
13

Вы можете передать его как обычный реквизит: foo={<ComponentOne />}

Например:

const ComponentOne = () => <div>Hello world!</div>
const ComponentTwo = () => (
  <div>
    <div>Hola el mundo!</div>
    <ComponentThree foo={<ComponentOne />} />
  </div>
)
const ComponentThree = ({ foo }) => <div>{foo}</div>
Незнакомец
источник
9

Я предпочитаю использовать встроенный API React:

import React, {cloneElement, Component} from "react";
import PropTypes from "prop-types";

export class Test extends Component {
  render() {
    const {children, wrapper} = this.props;
    return (
      cloneElement(wrapper, {
        ...wrapper.props,
        children
      })
    );
  }
}

Test.propTypes = {
  wrapper: PropTypes.element,
  // ... other props
};

Test.defaultProps = {
  wrapper: <div/>,
  // ... other props
};

тогда вы можете заменить div-обертку тем, что вы хотите:

<Test wrapper={<span className="LOL"/>}>
  <div>child1</div>
  <div>child2</div>
</Test> 
Фарид Алнамрути
источник
5

Вы можете передать компонент через. реквизит и рендеринг с интерполяцией.

var DivWrapper = React.createClass({
    render: function() {
        return <div>{ this.props.child }</div>;
    }
});

Затем вы передадите propвызванный child, который будет компонентом React.

returneax
источник
1
Это приведет к передаче компонентов через атрибуты, а не как дочерние элементы. Если вы используете this.props.childrenкак предложено в другом ответе, вы можете написать детей как дети, а не attrs.
Росс Аллен
1
@ssorallen вы не сказали, почему кто-то лучше ... Передавая его как реквизит, вы даже можете дать ему имя и использовать propTypes для проверки типов.
returneax
1
Каждый элемент, который вы используете в JSX, является просто компонентом. Если бы они использовали этот подход, вы не смогли бы написать даже свой короткий пример. Это стало бы <div child={this.props.child />.
Росс Аллен
1
Проверьте версию JavaScript (во что JSX превращает ее): jsfiddle.net/ssorallen/kvrxcqv8/2 . React.DOM.divКак и все основные компоненты, использует childrenмассив. Посмотрите, как он используется в вашем Helloкомпоненте, он уже использует несколько дочерних элементов.
Росс Аллен
20
Недостатком продолжения обсуждения в чате является то, что они не архивируются для будущих читателей.
ultrafez
3

Позднее с игрой, но вот мощный шаблон HOC для переопределения компонента, предоставляя его в качестве опоры. Это просто и элегантно.

предполагать MyComponent рендерит вымышленный Aкомпонент, но вы хотите разрешить пользовательское переопределение A, в этом примере B, которое переносится Aв a, <div>...</div>а также добавляет "!" к текстовой опоре:

import A from 'fictional-tooltip';

const MyComponent = props => (
  <props.A text="World">Hello</props.A>
);
MyComponent.defaultProps = { A };

const B = props => (
  <div><A {...props} text={props.text + '!'}></div>
);

ReactDOM.render(<MyComponent A={B}/>);
joneit
источник
1

На самом деле, ваш вопрос заключается в том, как написать компонент высшего порядка (HOC). Основная цель использования HOC - предотвращение копирования. Вы можете написать свой HOC как чисто функциональный компонент или как класс, вот пример:

    class Child extends Component {
    render() {
        return (
            <div>
                Child
            </div>
        );
    }
}

Если вы хотите написать свой родительский компонент как компонент на основе классов:

    class Parent extends Component {
    render() {
        return (
            <div>
                {this.props.children}
            </div>
        );
    }
}

Если вы хотите написать своего родителя как функциональный компонент:

    const Parent=props=>{
    return(
        <div>
            {props.children}
        </div>
    )
}
Мейсам Назари
источник
0

Ниже приведен пример родительского компонента реагирования List , в котором реквизиты содержат элемент реагирования. В этом случае передается только один компонент реакции Link (как видно из dom render).

class Link extends React.Component {
  constructor(props){
    super(props);
  }
  render(){
    return (
      <div>
        <p>{this.props.name}</p>
      </div>
     );
  }
}
class List extends React.Component {
  render(){
   return(
    <div>
       {this.props.element}
       {this.props.element}
    </div>
   );
  }
}

ReactDOM.render(
  <List element = {<Link name = "working"/>}/>,
  document.getElementById('root')
);
cheesey
источник
0

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

Дипанкар Датта
источник
1
Можете