我们说我有一个简单的反应组件:
import React from 'react';
import styles from "./index.css";
export default React.createClass({
render: function() {
return (
<header className={styles.root}>
// area for child content
{this.props.children}
</header>
);
}
});
现在让我们说代替任何子组件的一个区域,我想要两个,就像这样:
import React from 'react';
import styles from "./index.css";
export default React.createClass({
render: function() {
return (
<header className={styles.root}>
<div className={styles.logo}>
// logo children here
</div>
<div>
// navigation children here
</div>
</header>
);
}
});
我知道我可以使用属性,但对于大量的html内容来说,这不会很优雅。如何通过类似于例如swig中named blocks的方式做出反应?
命名块的示例:
{% extends 'layout.html' %}
{% block title %}My Page{% endblock %}
{% block head %}
{% parent %}
<link rel="stylesheet" href="custom.css">
{% endblock %}
{% block content %}
<p>This is just an awesome page.</p>
{% endblock %}
您可以通过参考他们的名字来使用这些块,从而允许这些块产生&#39;多个领域的内容。我希望有一种同样优雅的方式来做到这一点,因为它使组件非常易于组合。
答案 0 :(得分:18)
import React, { Component } from 'react';
import styles from "./index.css";
import Logo from "./components/Logo";
import Navbar from "./components/Logo";
class Comp extends Component {
render(){
return (
<Header className={styles.root}
top={Logo}
right={Navbar}
/>
);
}
}
class Header extends Component {
render(){
let {top,right} =this.props;
return (
<header className={styles.root}>
<div className={styles.logo}>
{top && <top />}
</div>
<div>
{right && <right />}
</div>
</header>
);
}
}
答案 1 :(得分:11)
Make seperate components Donot use props to pass components as children.
something like this.
// header.js
import React from 'react';
import styles from "./index.css";
export default React.createClass({
getComponent(key) {
return this.props.children.filter( (comp) => {
return comp.key === key;
});
}
render: function() {
return (
<header className={styles.root}>
<div className={styles.logo}>
{this.getComponent('logo')}
</div>
<div>
{this.getComponent('navbar'}
</div>
</header>
);
}
});
// app.js
export default React.createClass({
render: function() {
return (
<Header>
<Logo key="logo"/>
<Navbar key="navbar"/>
</Header>
);
}
});
答案 2 :(得分:1)
您可以将道具视为儿童,因为技术上children
只是另一个道具。这种方法没有错 - React贡献者自己建议你这样做(Support multiple child insertion points)。
此外,如果你在一个庞大的工程师团队中工作,我还建议标准化你如何命名这些道具以及他们的标准行为 - 他们只是简单的内容或回调你可以传递参数。 react-placeholders可以帮助您。因此,组件的代码可能如下所示:
// header.jsx
import React from 'react';
import withSlots from 'react-placeholders';
@withSlots('logo', 'navigation')
export default class Header extends React.Component {
render() {
return (
<header className={styles.root}>
<div className={styles.logo}>
{this.props.header()}
</div>
<div>
{this.props.navigation('home')}
</div>
</header>
);
}
}
这就是你嵌入该组件的方式
// app.jsx
import Header from 'header.jsx'
export default class Header extends React.Component {
render() {
return (
<Header
logoSlot={<img src="logo.svg" />}
navigationSlot={(currentPage) => {
return <a href="#" style={{ color: currentPage ? 'blue' : 'red' }}>Home</a>
}}
/>
);
}
}
答案 3 :(得分:0)
这个问题启发了我。这是我的方法:
第一个子组件:TestA.tsx
import * as React from 'react';
export default class TestA extends React.Component {
render () {
return (
<div className="TestA">{this.props.children}</div>
)
}
}
第二个子组件:TestB.tsx
import * as React from 'react';
export default class TestB extends React.Component {
render () {
return (
<div className="TestB">{this.props.children}</div>
)
}
}
父组件:TestAB.tsx
import * as React from 'react';
type TestABProps = {
children: React.ReactNode;
}
export default class TestAB extends React.Component<TestABProps> {
//Loop through React nodes in children and get all instances of the specified component
getComp( comp: string ): null | React.ReactNode | React.ReactNode[] {
if( this.props.children instanceof Array ) {
let nodes: React.ReactNode[] = [];
for( let child of this.props.children ) {
if( ((child as React.ReactElement)?.type as Function)?.name == comp ) {
nodes.push( child );
}
}
return nodes.length > 1 ? nodes : nodes[0];
}
return null;
}
render () {
return (
<div className="AB">
<div className ="A">
{this.getComp("TestA")}
</div>
<div>This is a DIV between the components</div>
<div className ="B">
{this.getComp("TestB")}
</div>
</div>
)
}
}
如您所见,您只需要将{this.getComp("YourComponentName")}
放置在希望该组件的所有实例出现在父组件中的位置。
用法示例
<TestAB>
<TestA>Foo</TestA>
<TestB>Bar</TestB>
<TestA>Foobar</TestA>
</TestAB>
用法非常简单直观。不需要键或其他任何东西,只需插入您的子组件而无需使用怪异的语法即可。
生成的HTML
<div class="AB">
<div class="A">
<div class="TestA">Foo</div>
<div class="TestA">Foobar</div>
</div>
<div>This is a DIV between the components</div>
<div class="B">
<div class="TestB">Bar</div>
</div>
</div>
请注意,您可以按任意顺序插入TestAB的子级-它们将插入正确的位置。
所有这些都可以改进,您可以根据需要进行调整。例如,如果您放置除TestA或TestB之外的任何子组件,则不会显示它们,这是我的第一个改进。