React第十二章 组件复合

193 阅读3分钟

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!