如何将一个反应组件传递给另一个反应组件以包含第一个组件的内容?
Posted
技术标签:
【中文标题】如何将一个反应组件传递给另一个反应组件以包含第一个组件的内容?【英文标题】:How to pass in a react component into another react component to transclude the first component's content? 【发布时间】:2014-11-05 23:15:53 【问题描述】:有没有办法将一个组件传递给另一个反应组件?我想创建一个模型反应组件并传入另一个反应组件以嵌入该内容。
编辑:这是一个 reactJS 代码笔,说明了我正在尝试做的事情。 http://codepen.io/aallbrig/pen/bEhjo
<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'));
【问题讨论】:
【参考方案1】:您可以使用this.props.children
来渲染组件包含的任何子组件:
const Wrap = ( children ) => <div>children</div>
export default () => <Wrap><h1>Hello word</h1></Wrap>
【讨论】:
我会使用这个答案。this.props.children
是组件 API 的一部分,预计会以这种方式使用。 React 团队的示例使用了这种技术,例如在 transferring props 和谈论 single child 时。
来自我下面的评论:通过将其作为道具传递,您甚至可以为其命名并使用 propTypes 进行类型检查。
@AndrewAllbright:你的例子没有传递任何孩子。这有效:codepen.io/ssorallen/pen/Dyjmk
如果你想获得孩子的 DOM 节点:***.com/questions/29568721/…【参考方案2】:
注意我提供了更深入的答案here
运行时包装器:
这是最惯用的方式。
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
您可以使用Higher Order Component (HOC)。他们最近被添加到official doc。
// 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 提前一步使渲染短路,而在运行时包装器的情况下,children prop 可能始终是不同的 ReactElement 并导致即使您的组件扩展了 PureComponent,也会重新渲染。
请注意,Redux 的 connect
曾经是运行时包装器,但已更改为 HOC,因为如果您使用 pure
选项(默认情况下为 true),它可以避免无用的重新渲染
你不应该在渲染阶段调用 HOC,因为创建 React 组件可能会很昂贵。您应该在初始化时调用这些包装器。
请注意,当使用上述功能组件时,HOC 版本不提供任何有用的优化,因为无状态功能组件不实现shouldComponentUpdate
更多解释在这里:https://***.com/a/31564812/82609
【讨论】:
【参考方案3】: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 ); import MyComponent from //...where ever const myComponent =您可以将其作为普通道具传递: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>
【讨论】:
【参考方案5】:Facebook 推荐使用无状态组件 来源:https://facebook.github.io/react/docs/reusable-components.html
在理想情况下,您的大部分组件都是无状态的 功能,因为在未来我们也将能够做出表现 通过避免不必要的特定于这些组件的优化 检查和内存分配。这是推荐的模式,当 可能。
function Label(props)
return <span>props.label</span>;
function Hello(props)
return <div>props.labelprops.name</div>;
var hello = Hello(name:"Joe", label:Label(label:"I am "));
ReactDOM.render(hello,mountNode);
【讨论】:
【参考方案6】:我更喜欢使用 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>
【讨论】:
【参考方案7】:你可以通过传入一个组件。道具并用插值渲染它。
var DivWrapper = React.createClass(
render: function()
return <div> this.props.child </div>;
);
然后您将传入一个名为 child
的 prop
,这将是一个 React 组件。
【讨论】:
这将导致通过属性而不是子组件传递组件。如果您按照另一个答案中的建议使用this.props.children
,则可以将孩子写为孩子而不是attrs。
@ssorallen 你没有说为什么一个更好......通过将它作为道具传递,你甚至可以给它一个名称并使用 propTypes 进行类型检查。
你在 JSX 中使用的每个元素都只是一个组件。如果他们使用这种方法,您甚至无法编写简短的示例。它会变成<div child=this.props.child />
。
查看 javascript 版本(JSX 将其转换成什么):jsfiddle.net/ssorallen/kvrxcqv8/2。 React.DOM.div
与所有核心组件一样,使用children
数组。看看它在你的 Hello
组件中是如何使用的,它已经在使用多个子组件了。
在聊天中继续讨论的缺点是它们不会为未来的读者存档。【参考方案8】:
游戏迟到了,但这里有一个强大的 HOC 模式,用于通过将组件作为道具提供来覆盖组件。它简单而优雅。
假设MyComponent
呈现一个虚构的A
组件,但您希望允许自定义覆盖A
,在此示例中为B
,它将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/>);
【讨论】:
【参考方案9】:实际上,您的问题是如何编写高阶组件 (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>
)
【讨论】:
【参考方案10】:这里是一个父 List react 组件的示例,并且 whos 的 props 包含一个 react 元素。在这种情况下,只传入了一个 Link 反应组件(如 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')
);
【讨论】:
【参考方案11】:您可以将组件作为道具传递,并使用与使用组件相同的方式。
function General(props)
...
return (<props.substitute a=A b=B />);
function SpecificA(props) ...
function SpecificB(props) ...
<General substitute=SpecificA />
<General substitute=SpecificB />
【讨论】:
【参考方案12】:您可以将您的反应组件传递给另一个组件并从子组件发出函数
import CustomerFilters;
parent:
const handleFilterChange = (value) =>
console.log(value)
<DataGrid
contentName="customer"
fetchFilterComponents = <CustomerFilters onSelectFilter=handleFilterChange />
</DataGrid>
child:
CustomerFilters
return (
<select className="filters-dropdown" onChange=onSelectFilter>
<option>Select Filter</option>
customerFilterOptions?.map((filter: any) =>
return <option value=filter.value>filter.name</option>;
)
</select>
)
【讨论】:
请解释一下你想用这段代码做什么。以上是关于如何将一个反应组件传递给另一个反应组件以包含第一个组件的内容?的主要内容,如果未能解决你的问题,请参考以下文章
Apollo/graphQL:如何将乐观 UI 用于嵌套反应组件的突变?
如何将输入值从子表单组件传递到其父组件的状态以使用反应钩子提交?