vuepress-theme-vdoing/docs/《React》笔记/01.核心概念/10.组合vs继承.md

203 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: 组合vs继承
date: 2021-03-26 12:56:40
permalink: /pages/9ae8e8/
categories:
- 《React》笔记
- 核心概念
tags:
- React
author:
name: xugaoyi
link: https://github.com/xugaoyi
---
# 10.组合vs继承
React 有十分强大的组合模式。我们**推荐使用组合而非继承来实现组件间的代码重用**。
## 包含关系 (组件组合)
有些组件无法提前知晓它们子组件的具体内容。在 `Sidebar`(侧边栏)和 `Dialog`对话框等展现通用容器box的组件中特别容易遇到这种情况。
### props的children属性类似vue的插槽
我们建议这些组件使用一个**特殊的 `children` prop 来将他们的子组件传递到渲染结果中**
```jsx
function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
// children 是特殊的prop在父组件中没有显式声明
{props.children}
</div>
);
}
function WelcomeDialog() {
return (
<FancyBorder color="blue">
// 子组件标签之间的内容被当做 props.children 传入
<h1 className="Dialog-title">
Welcome
</h1>
<p className="Dialog-message">
Thank you for visiting our spacecraft!
</p>
</FancyBorder>
);
}
```
:::note
类似于vue中的插槽
:::
### props传入组件类似vue命名插槽
少数情况下,你可能需要在一个组件中预留出几个“洞”。这种情况下,我们可以不使用 `children`,而是自行约定:将所需内容传入 props并使用相应的 prop。
```jsx
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left}
</div>
<div className="SplitPane-right">
{props.right}
</div>
</div>
);
}
function App() {
// props传入组件
return (
<SplitPane
left={
<Contacts />
}
right={
<Chat />
} />
);
}
```
`<Contacts />``<Chat />` 之类的 React 元素本质就是对象object所以你可以把它们当作 props像其他数据一样传递。**你可以将任何格式的数据作为 props 进行传递。**
:::note
类似于vue中的命名插槽
:::
## 特例关系(字符串与组件组合)
有些时候,我们会把一些组件看作是其他组件的特殊实例,比如 `WelcomeDialog` 可以说是 `Dialog` 的特殊实例。
在 React 中,我们也可以通过组合来实现这一点。“特殊”组件可以通过 props 定制并渲染“一般”组件:
```jsx
function Dialog(props) {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
// 这里props.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方式的组件组合
组合也同样适用于以 class 形式定义的组件。
```jsx
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}!`);
}
}
```
## 那么继承呢?(不推荐)
在 Facebook我们在成百上千个组件中使用 React。我们并没有发现需要使用继承来构建组件层次的情况。
Props 和组合为你提供了清晰而安全地定制组件外观和行为的灵活方式。**注意:组件可以接受任意 props包括基本数据类型React 元素以及函数**。
如果你想要在组件间复用非 UI 的功能,我们建议将其提取为一个单独的 JavaScript 模块如函数、对象或者类。组件可以直接引入import而**无需通过 extend 继承它们**。