吴志勇的博客 吴志勇的博客
  • h5

    • HTML5&CSS3
  • scss

    • css预处理语言
  • JavaScript

    • JavaScript教程
    • Ajax
    • ES6教程
    • NodeJS
    • Typescript
  • 框架

    • Jquery
    • VUE
    • React
  • Swing专题
  • java基础
  • javaweb
  • 框架
  • 数据库
  • netty
  • 设计模式
  • 微服务及架构
  • 云原生
  • maven
  • 单元测试
工具
我的
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

吴志勇

......
  • h5

    • HTML5&CSS3
  • scss

    • css预处理语言
  • JavaScript

    • JavaScript教程
    • Ajax
    • ES6教程
    • NodeJS
    • Typescript
  • 框架

    • Jquery
    • VUE
    • React
  • Swing专题
  • java基础
  • javaweb
  • 框架
  • 数据库
  • netty
  • 设计模式
  • 微服务及架构
  • 云原生
  • maven
  • 单元测试
工具
我的
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • HTML5&CSS3

  • CSS预处理语言

  • JavaScript

  • nodejs

  • webpack

  • VUE

  • react

    • 01 【react入门】
    • 02 【面向组件编程】
    • 03 【事件处理】
    • 04 【生命周期】
    • 05 【条件渲染】
    • 06 【列表 & Key】
    • 07 【收集表单数据】
    • 08 【状态提升】
    • 09 【组合组件】
      • 1.包含关系
      • 2.特例关系问题
    • 10 【初始化脚手架】
    • 11 【react-router 5】
    • 12 【react高级指引(上)】
    • 13【react高级指引(下)】
    • 14【react-Hook (上)】
    • 15【react-Hook (下)】
    • 16 【react-router 6】
    • 17【redux】
    • 18 【Redux Toolkit】
    • 19 【RTK Query】
    • 20 【react中使用ts】
    • 21 【styled-components的使用】
    • 22 【在react中使用Emotion】
    • 23 【UmiJS入门】
    • 24 【UmiJS基础】
  • Typescript
  • 前端
  • react
wuzhiyong
2024-09-22

09 【组合组件】

# 09 【组合组件】

# 1.包含关系

有些组件无法提前知晓它们子组件的具体内容。在 Sidebar(侧边栏)和 Dialog(对话框)等展现通用容器(box)的组件中特别容易遇到这种情况。

我们建议这些组件使用一个特殊的 children prop 来将他们的子组件传递到渲染结果中:

组件标签里面包含的子元素会通过 props.children 传递进来。

function One(props) {
 return (
    <div>{props.children}</div>
    //特殊的children props
  );
}

function Two(props) {
  return (
  //这使别的组件可以通过JSX嵌套,来将任意组件作为子组件来传递给他们
  <One>
      <div>Hello</div>
      <div>World</div>
  </One>
);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

image-20221025135313079

# 2.特例关系问题

有些时候,我们会把一些组件看作是其他组件的特殊实例,比如 WelcomeDialog 可以说是 Dialog 的特殊实例。

在 React 中,我们也可以通过组合来实现这一点。“特殊”组件可以通过 props 定制并渲染“一般”组件:

.FancyBorder {
  padding: 10px 10px;
  border: 10px solid;
}

.FancyBorder-blue {
  border-color: blue;
}

.Dialog-title {
  margin: 0;
  font-family: sans-serif;
}

.Dialog-message {
  font-size: larger;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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!" />
  );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

在 CodePen 上尝试 (opens new window)

组合也同样适用于以 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}!`);
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

在 CodePen 上尝试 (opens new window)

image-20221025135929891

上次更新: 2024-09-30 01:09:25

← 08 【状态提升】 10 【初始化脚手架】→

Copyright © 2020-2026 wuzhiyong
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式