Composition 组件复合 重要
1、官方文档,必读必读必读!(组合vs继承)
React 有十分强大的组合模式。我们推荐使用组合而非继承来实现组件间的代码重用。
2、个人理解 (组合vs继承)
组合:是在基础组件上,再包一层,并为基础组件传递各种属性(props)可以是基础组件(内的jsx,或 外的属性)。
例如:梁上兄弟聚义,组合起来干大事;相互补充长短条件和功能;有统筹全局的、有负责片区的、有负责具体事情的。(国家体系、航母编队)
常用在 UI层
继承:是在父类上,扩展一个子类,子类可以(不重写直接用父类方法和属性;重写父类方法;定义自己的私有属性方法;一层层包,一层层扩展)
例如:家族几代人共同创业完成一系列功能,每一代都有各自的多多少少功能和特色。(摩根财团、大家族)
常用在 逻辑层
2.1、包含关系
<Contacts /> 和 <Chat /> 之类的 React 元素本质就是对象(object),
所以你可以把它们当作 props,像其他数据一样传递。
这种方法可能使你想起别的库(Vue)中“槽”(slot)的概念,
但在 React 中没有“槽”这一概念的限制,你可以将任何东西作为 props 进行传递。
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 />
} />
);
}
2.2、特例关系
有些时候,我们会把一些组件看作是其他组件的特殊实例,比如 WelcomeDialog 可以说是 Dialog 的特殊实例。
在 React 中,我们也可以通过组合来实现这一点。
“特殊”组件可以通过 props 定制并渲染“一般”组件:
function中使用:
function Dialog(props) {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
{props.title}
</h1>
<p className="Dialog-message">
{props.message}
</p>
</FancyBorder>
);
}
function WelcomeDialog() {
return (
<Dialog
title="Welcome"
message="Thank you for visiting our spacecraft!" />
);
}
class 中使用:
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}!`);
}
}
2、概念
antd design 中 、 等等只要是双标签都是 组件复合的使用
<Button type="dashed">Dashed Button</Button>
<Card title="Default size card" extra={<a href="#">More</a>} style={{ width: 300 }}>
<p>Card content</p>
<p>Card content</p>
<p>Card content</p>
</Card>
3、使用
3.1、不具名
// 基础组件
function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children}
</div>
);
}
// 具体使用组件
function WelcomeDialog() {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
Welcome
</h1>
<p className="Dialog-message">
Thank you for visiting our spacecraft!
</p>
</FancyBorder>
);
}
3.2、具名 (传个对象进去)
// 基础组件
import React, { Component } from "react";
import TopBar from "../components/TopBar";
import BottomBar from "../components/BottomBar";
export default class Layout extends Component {
componentDidMount() {
const { title = "商城" } = this.props;
document.title = title;
}
render() {
const { children, showTopBar, showBottomBar } = this.props;
return <div>
{showTopBar && <TopBar />}
{children.content}
{children.txt}
<button onClick={children.btnClick}>点击事件</button>
{showBottomBar && <BottomBar />}
</div>
}
}
// 具体使用组件
import React, { Component } from "react";
import Layout from "./Layout";
export default class HomePage extends Component {
render() {
return <Layout showTopBar={false} showBottomBar={true} title="商城⻚">
{{
content: (<div><h3>HomePage</h3></div>),
txt: "这是个⽂文本",
btnClick: () => {}
}}
</Layout>
}
}
4、那么继承呢?
在 Facebook,我们在成百上千个组件中使用 React。我们并没有发现需要使用继承来构建组件层次的情况。
Props 和组合为你提供了清晰而安全地定制组件外观和行为的灵活方式。
注意:组件可以接受任意 props,包括基本数据类型,React 元素以及函数。
如果你想要在组件间复用非 UI 的功能,我们建议将其提取为一个单独的 JavaScript 模块,如函数、对象或者类。
组件可以直接引入(import)而无需通过 extend 继承它们。good!