组合vs继承
React 有十分强大的组合模式。我们推荐使用组合而非继承来实现组件间的代码重用。
props.children
有些组件无法提前知晓它们子组件的具体内容。在 Sidebar
(侧边栏)和 Dialog
(对话框)等展现通用容器(box)的组件中特别容易遇到这种情况。
我们建议这些组件使用一个特殊的 children
prop 来将他们的子组件传递到渲染结果中:
class SideBarItems extends React.Component {
render(){
return (
<ul>
<li>首页</li>
<li>用户管理</li>
<li>商品管理</li>
<li>内容管理</li>
</ul>
)
}
}
class SideBar extends React.Component {
constructor(props){
super(props);
}
render(){
return (
<div>
{this.props.children}
</div>
)
}
}
class Content extends React.Component {
render(){
return (
<div>
这是内容部分
</div>
)
}
}
class FootBar extends React.Component {
render(){
return (
<div>
这是底部部分
</div>
)
}
}
class BaseLayout extends React.Component {
constructor(props){
super(props);
}
render(){
return (
<div>
{/*props.children是默认熟悉,指当前组件标签的内容部分*/}
{this.props.children}
</div>
)
}
}
class HelloWorld extends React.Component {
render(){
return (
<div>
{/*类似于vue的插槽slot */}
<BaseLayout>
<SideBar>
<SideBarItems/>
</SideBar>
<Content/>
<FootBar/>
</BaseLayout>
</div>
)
}
}
// 通过调用React自身方法render可以得到当前组件的实例对象,并渲染到页面容器.
ReactDOM.render(<App />, document.getElementById("root"));
具名插槽
少数情况下,你可能需要在一个组件中预留出几个“洞”。这种情况下,我们可以不使用children,而是自行约定:将所需内容传入 props,并使用相应的 prop。
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left}
</div>
<div className="SplitPane-right">
{props.right}
</div>
</div>
);
}
function App() {
return (
<SplitPane
left={
<Contacts />
}
right={
<Chat />
} />
);
}
特例关系
function Dialog(props) {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
{props.title}
</h1>
<p className="Dialog-message">
{props.message}
</p>
{props.children}
</FancyBorder>
);
}
class SignUpDialog extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleSignUp = this.handleSignUp.bind(this);
this.state = {login: ''};
}
render() {
return (
<Dialog title="Mars Exploration Program"
message="How should we refer to you?">
<input value={this.state.login}
onChange={this.handleChange} />
<button onClick={this.handleSignUp}>
Sign Me Up!
</button>
</Dialog>
);
}
handleChange(e) {
this.setState({login: e.target.value});
}
handleSignUp() {
alert(`Welcome aboard, ${this.state.login}!`);
}
}