如何将一个反应成分传递到另一个反应成分中以超越第一成分的含量?


214

有没有办法将一个组件传递到另一个React组件?我想创建一个模型react组件,并传入另一个react组件以包含该内容。

编辑:这是一个reactJS codepen,说明了我正在尝试做的事情。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'));

Answers:


196

您可以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 2014年

1
@AndrewAllbright:您的示例没有传递任何孩子。这项工作:codepen.io/ssorallen/pen/Dyjmk
Ross Allen

而如果你那么想获得孩子们的DOM节点:stackoverflow.com/questions/29568721/...
ericsoco

122

注意我在这里提供了更深入的答案

运行时包装器:

这是最惯用的方式。

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。

请注意,connectRedux曾经是运行时包装程序,但已更改为HOC,因为如果使用该pure选项,它可以避免无用的重新渲染(默认情况下为true)

在渲染阶段绝对不要调用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} />
Andrew Allbright

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);

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

我更喜欢使用React内置的API:

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组件。


1
这将导致通过属性而不是作为子元素来传递组件。如果this.props.children按照其他答案中的建议使用,则可以将子代写为子代而不是attrs。
罗斯·艾伦

1
@ssorallen您没有说过为什么它会更好...通过将它作为道具传递,您甚至可以给它起一个名字并使用propTypes进行类型检查。
returneax 2014年

1
您在JSX中使用的每个元素都只是一个组件。如果他们使用这种方法,那么即使是简短的示例,您也将无法编写。它将成为<div child={this.props.child />
罗斯·艾伦

1
查看JavaScript版本(JSX将其转换成什么):jsfiddle.net/ssorallen/kvrxcqv8/2React.DOM.div与所有核心组件一样,都使用children数组。看一下它在Hello组件中的用法,它已经在使用多个子级了。
罗斯·艾伦

20
继续在聊天中进行讨论的不利之处在于,它们不会为将来的读者存档。
ultrafez

3

游戏晚了,但是这里有一个强大的HOC模式,可通过将其作为道具来覆盖组件。简单而优雅。

假设MyComponent呈现一个虚构的A组件,但您想允许对的自定义覆盖A,在本示例中B,该包裹包含Aa <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}/>);

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 react组件的示例,并且whos道具包含react元素。在这种情况下,仅传入一个Link react组件(如dom渲染中所示)。

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')
);

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.